# How to Configure Custom Component Registries for Internal Company Components

> Learn to configure custom component registries for internal company components. Easily add and install your own UI elements using shadcn-ui with this simple guide.

- Repository: [shadcn-ui/ui](https://github.com/shadcn-ui/ui)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Add a namespaced URL to the `registries` field in your [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) file, ensure your server exposes the required JSON endpoints, and install internal components using `npx shadcn add @company/component`.**

Shadcn UI discovers UI components through a **registry system** implemented in the `shadcn-ui/ui` repository. While the CLI ships with a built-in `@shadcn` registry, enterprises can configure **custom component registries** to distribute internal design systems across teams. By editing [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) and exposing a simple HTTP contract, you can consume private components exactly like public ones.

## Understanding the Registry Architecture

Registries are **namespaced collections** that map to URL endpoints. The CLI maintains the default registry map in [`packages/shadcn/src/registry/constants.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/registry/constants.ts) as the constant `BUILTIN_REGISTRIES`.

At runtime, the configuration loader in [`packages/shadcn/src/utils/get-config.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/utils/get-config.ts) merges built-in and user-defined registries inside the `resolveConfigPaths` function:

```ts
config.registries = {
  ...BUILTIN_REGISTRIES,
  ...(config.registries || {})
};

```

This merge operation ensures your internal entries coexist with the public index while taking precedence in resolution order.

## Configuring Your Internal Registry

### Define the Registry Endpoints

Your registry server must implement a minimal HTTP contract. The CLI expects two specific endpoints:

- `GET /registry` – Returns metadata including `name`, `homepage`, and an `items` array describing available components
- `GET /registry/<item>.json` – Returns the full component definition including files, dependencies, and registry type

The resolver substitutes the `{name}` placeholder in your configured URL with the specific component identifier when fetching definitions. For example, a URL template `https://registry.mycompany.com/registry/{name}` becomes `https://registry.mycompany.com/registry/button.json` when installing a component named `button`.

### Register in components.json

Edit your project’s [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) to include the `registries` object:

```json
{
  "registries": {
    "@mycompany": "https://registry.mycompany.com/registry/{name}"
  }
}

```

The namespace (`@mycompany`) becomes the prefix for all CLI commands targeting this registry. The `{name}` placeholder is required and is dynamically replaced by the resolver logic in [`packages/shadcn/src/registry/resolver.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/registry/resolver.ts).

### Verify Registry Discovery

Before executing installation commands, the CLI invokes `ensureRegistriesInConfig()` from [`packages/shadcn/src/utils/registries.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/utils/registries.ts). This utility performs three critical operations:

1. Calls `resolveRegistryNamespaces()` to identify all required registries (including transitive dependencies)
2. Filters out existing entries present in `BUILTIN_REGISTRIES` or the current config
3. Fetches missing registry URLs from the public index and automatically persists them to [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) (unless the `writeFile` option is disabled)

This automatic persistence ensures new team members receive registry configurations without manual file edits.

## Authentication Support

Enterprise registries can require authentication without additional CLI configuration. The resolver in [`packages/shadcn/src/registry/resolver.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/registry/resolver.ts) automatically detects and forwards auth headers when your registry URL contains specific path segments:

- `/bearer/`
- `/api-key/`
- `/client-secret/`

When these patterns are present, the CLI forwards the appropriate authentication headers from environment variables or CLI flags, enabling secure access to private component registries.

## Minimal Registry Implementation

The test suite in [`packages/tests/src/utils/registry.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/tests/src/utils/registry.ts) provides a complete reference implementation. Below is the essential structure for a Node.js HTTP server that satisfies the CLI requirements:

```ts
import { createServer } from "http";

export async function createRegistryServer(items: Array<any>) {
  const server = createServer((request, response) => {
    const urlRaw = request.url?.split("?")[0];

    // Serve registry index
    if (urlRaw?.endsWith("/registry")) {
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(
        JSON.stringify({
          name: "Internal Registry",
          homepage: "https://registry.mycompany.com",
          items,
        })
      );
      return;
    }

    // Serve individual component definition
    if (urlRaw?.match(/\/registry\/.*\.json$/)) {
      const componentName = urlRaw.match(/\/registry\/(.*)\.json$/)?.[1];
      const item = items.find((i) => i.name === componentName);
      
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify(item));
      return;
    }

    response.writeHead(404);
    response.end(JSON.stringify({ error: "Not found" }));
  });

  return {
    start: () => new Promise<void>((res) => server.listen(4444, res)),
    stop: () => new Promise<void>((res) => server.close(() => res())),
  };
}

```

This implementation handles the `{name}` substitution pattern and supports the JSON schema expected by [`packages/shadcn/src/registry/resolver.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/registry/resolver.ts).

## Using Internal Components

Once your registry is configured, install components using the namespace prefix:

```bash

# Install a component from your internal registry

npx shadcn add @mycompany/button

# View component details

npx shadcn view @mycompany/card

# Search your internal catalog

npx shadcn search @mycompany/

```

The CLI resolves the `@mycompany` namespace to your configured URL, replaces `{name}` with the component identifier, fetches the definition, and writes the files to your project's `components` alias directory. The system automatically updates your import map and respects your existing `tailwind.config` and TypeScript paths.

## Summary

- **Custom component registries** are configured in [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) using namespaced URLs with a required `{name}` placeholder
- The CLI merges user registries with `BUILTIN_REGISTRIES` in [`packages/shadcn/src/utils/get-config.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/utils/get-config.ts) at configuration load time
- Required endpoints are `GET /registry` for metadata and `GET /registry/<item>.json` for component definitions
- Authentication is automatically handled for URLs containing `/bearer/`, `/api-key/`, or `/client-secret/` patterns
- The `ensureRegistriesInConfig()` function in [`packages/shadcn/src/utils/registries.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/utils/registries.ts) automatically persists missing registry entries to [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json)
- Install internal components using namespace prefixes: `npx shadcn add @company/component`

## Frequently Asked Questions

### How do I secure my internal registry behind corporate authentication?

Include authentication segments directly in the registry URL stored in [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json). The resolver in [`packages/shadcn/src/registry/resolver.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/registry/resolver.ts) automatically detects URLs containing `/bearer/`, `/api-key/`, or `/client-secret/` and forwards the appropriate headers. Store sensitive tokens in environment variables and reference them in the URL configuration.

### Can I use a static JSON file instead of an HTTP server for my registry?

Yes, you can host a static [`registry.json`](https://github.com/shadcn-ui/ui/blob/main/registry.json) file on any CDN or internal file server. Ensure the JSON structure includes the required `name`, `homepage`, and `items` fields. Configure your [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) to point directly to the file pattern: `"@mycompany": "https://cdn.mycompany.com/static/registry/{name}.json"`.

### What happens if an internal component depends on another registry?

The CLI resolves transitive dependencies automatically. When you invoke `ensureRegistriesInConfig()`, it calls `resolveRegistryNamespaces()` to detect all required registries across the entire dependency tree. Missing registries are fetched from the public index and added to your [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) before installation proceeds.

### Do developers need to manually edit [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) to add the registry?

No. The `ensureRegistriesInConfig()` function in [`packages/shadcn/src/utils/registries.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/utils/registries.ts) automatically writes missing registry entries to [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json) during the first CLI operation that references the namespace. Developers simply run `npx shadcn add @mycompany/component`, and the system persists the registry configuration automatically unless the `writeFile` option is explicitly disabled.