How to Configure Multiple Registries in shadcn/ui to Pull Components from Different Sources

You can configure multiple registries in shadcn/ui by adding entries to the registries field in your components.json file, allowing you to pull components from third-party sources, private APIs, and custom namespaces using the standard npx shadcn add command.

The shadcn/ui CLI supports a namespaced registry system that consolidates component sources from any HTTP-accessible endpoint into a single configuration. According to the shadcn-ui/ui source code, this architecture enables teams to distribute internal component libraries alongside the official registry without altering installation workflows. By declaring custom registries in components.json, you can execute npx shadcn add @namespace/component to pull from private repos, third-party design systems, or organization-specific APIs.

Understanding the Registry Architecture

Shadcn/ui implements a tiered registry system that separates built-in sources from user-defined configurations. This design ensures that the official registry remains accessible while allowing unlimited extension through custom namespaces.

Built-in Registry Protection

The CLI maintains the official shadcn registry as a protected constant. In packages/shadcn/src/registry/constants.ts (lines 32-35), the BUILTIN_REGISTRIES constant defines @shadcn as an immutable entry pointing to https://ui.shadcn.com/r/styles/{style}/{name}.json. This implementation prevents accidental overrides of the core registry, ensuring that standard components like button or input always resolve to the official source even when you configure multiple registries.

Configuration Merging Logic

When the CLI loads a project, the getConfig utility in packages/shadcn/src/utils/get-config.ts (lines 50-55) merges the built-in registries with your custom entries. This merge produces a unified config.registries map that the CLI consults for every component lookup. The process preserves the built-in definitions while appending your custom namespaces, creating a single source of truth for resolving @namespace/component syntax.

Setting Up Multiple Registries in components.json

The components.json file accepts a registries key that accepts both simple URL strings and advanced configuration objects. According to the documentation in apps/v4/content/docs/registry/namespace.mdx (lines 48-63), each registry entry maps a namespace to its endpoint pattern.

Here is a complete configuration demonstrating multiple registry types:

{
  "registries": {
    "@shadcn": "https://ui.shadcn.com/r/styles/{style}/{name}.json",
    "@acme-ui": "https://registry.acme.com/ui/{name}.json",
    "@acme-docs": "https://registry.acme.com/docs/{name}.json",
    "@private": {
      "url": "https://api.internal.com/registry/{name}.json",
      "headers": {
        "Authorization": "Bearer ${INTERNAL_TOKEN}"
      }
    }
  }
}
  • @shadcn: The built-in registry populated automatically by the CLI constants.
  • @acme-ui and @acme-docs: Public registries using simple string URLs where {name} is substituted with the component identifier.
  • @private: An object-format registry supporting authentication headers. The ${INTERNAL_TOKEN} syntax enables environment variable interpolation for secure credential management.

Adding Components from Custom Sources

Once configured, installing components from any registry uses the standard CLI syntax. The namespace prefix directs the resolver to the appropriate registry URL template.

Execute the following to add a component from a custom registry:

npx shadcn@latest add @acme-ui/button

The CLI resolves @acme-ui against your components.json, substitutes button into the URL template https://registry.acme.com/ui/{name}.json, and downloads the component definition. It then writes the component files to your project according to the downloaded schema.

Automatic Registry Discovery

The CLI includes automatic registry detection through the ensureRegistriesInConfig function in packages/shadcn/src/utils/registries.ts (lines 24-31 and 66-79). When you attempt to add a component from an unconfigured namespace, this utility fetches the registry URL from the global index and updates your components.json automatically.

This TypeScript example demonstrates the programmatic API for registry discovery:

import { ensureRegistriesInConfig } from "@/src/utils/registries";

await ensureRegistriesInConfig(
  ["@acme-ui/button", "@private/auth-utils"],
  config,
  { writeFile: true }
);

If @private was not previously listed in your configuration, the function resolves its URL from the global registry index and merges it into config.registries (see the merge logic at lines 66-79), then persists the changes to disk when writeFile is true.

Summary

  • You configure multiple registries by adding entries to the registries field in components.json, using either string URLs or object configurations with headers.
  • The @shadcn namespace is protected and defined in packages/shadcn/src/registry/constants.ts, ensuring the official registry remains available.
  • Configuration merging happens in packages/shadcn/src/utils/get-config.ts, combining built-in and user-defined registries into a single lookup map.
  • Automatic discovery via ensureRegistriesInConfig in packages/shadcn/src/utils/registries.ts can populate missing namespaces by querying the global index.
  • Authentication is supported through header objects in the registry configuration, with support for environment variable interpolation like ${INTERNAL_TOKEN}.

Frequently Asked Questions

Can I override the official shadcn registry?

No, the official @shadcn registry is protected by the BUILTIN_REGISTRIES constant in packages/shadcn/src/registry/constants.ts. This design prevents accidental overrides and ensures that core components always resolve to the official source, even when you configure multiple registries in your project.

How do I authenticate with private registries?

Use the object format in components.json to specify HTTP headers. You can include an Authorization header or other required credentials, and the CLI supports environment variable interpolation using the ${VAR_NAME} syntax. This allows you to reference tokens like ${INTERNAL_TOKEN} without committing secrets to version control.

What URL patterns are supported for custom registries?

Registries must provide JSON endpoints that follow the pattern defined in your configuration, typically containing a {name} placeholder that the CLI substitutes with the component identifier. The URL can include any valid HTTP or HTTPS address, supporting query parameters, subdomains, and path variables as needed for your API structure.

Does the CLI automatically detect new registry namespaces?

Yes, if you attempt to install a component from an unconfigured namespace, the CLI invokes ensureRegistriesInConfig from packages/shadcn/src/utils/registries.ts. This function checks the global registry index for the missing namespace, retrieves its URL configuration, and writes it back to your components.json file automatically, provided the registry is published to the index.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →