Shadcn Templates

How to Build and Publish Your Own shadcn/ui Registry

Updated 2026-10-27

A shadcn registry lets other developers install your components, blocks, hooks, themes and config files with one CLI command, as source code they can edit. You do not need a package on npm or a build pipeline beyond a single command. This guide walks through the files, the item types, the build step, hosting, and the official directory listing.

What a registry is made of

A registry has two kinds of JSON:

  • registry.json at the root, which names the registry and lists its items
  • One registry-item.json per item, generated by the build, which contains the item's metadata and the full content of its files

You write registry.json and your source files. The shadcn build command reads them and produces the per-item JSON files that the CLI fetches when someone runs shadcn add.

Step 1: Lay out your source files

The shadcn docs recommend placing each item under registry/[STYLE]/[NAME], where the style folder can be any name you choose:

registry/
  default/
    hello-world/
      hello-world.tsx
registry.json

Write imports inside registry files using the @/registry path. The CLI rewrites them to match the consumer's aliases on install.

Step 2: Write registry.json

The root file needs a name, a homepage, and either items or include:

{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "acme",
  "homepage": "https://acme.com",
  "items": [
    {
      "name": "hello-world",
      "type": "registry:block",
      "title": "Hello World",
      "description": "A simple hello world component.",
      "registryDependencies": ["button", "card"],
      "dependencies": ["motion"],
      "files": [
        {
          "path": "registry/default/hello-world/hello-world.tsx",
          "type": "registry:component"
        }
      ]
    }
  ]
}

Key fields on each item:

  • name: unique within your registry; this is what users type after the namespace
  • type: decides how the item is resolved and where files land (see below)
  • dependencies and devDependencies: npm packages, with optional @version
  • registryDependencies: other registry items, given as plain names (button), namespaced names (@acme/input-form), URLs or GitHub addresses
  • files: each with a path, a type and, where needed, a target

Write a clear title and description for every item. The docs point out that AI assistants using the shadcn MCP server rely on these to pick the right component.

For larger registries, split the file with include, which points to nested registry.json files. Paths in a nested file are relative to that file:

{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "acme",
  "homepage": "https://acme.com",
  "include": ["components/ui/registry.json", "hooks/registry.json"]
}

Step 3: Choose item types

The type field is the main decision for each item.

TypeUse it for
registry:uiUI components and single-file primitives
registry:componentSimple components
registry:blockComplex components with multiple files
registry:hookReact hooks
registry:libUtilities and libraries
registry:pagePages or file-based routes (requires target)
registry:fileMiscellaneous files such as config (requires target)
registry:styleRegistry styles such as new-york
registry:themeThemes (CSS variables)
registry:fontFonts, configured through the font field
registry:baseAn entire design system in one install
registry:itemUniversal items

A few practical notes:

  • Themes usually carry no files. They use cssVars, grouped under theme, light and dark, and the CLI merges them into the user's CSS file.
  • Fonts became a first-class type in shadcn CLI v4. A registry:font item uses the font field to set the family, provider, import name and CSS variable.
  • registry:base packages components, dependencies, CSS variables, fonts and config together, so a whole design system installs at once.

Controlling where files go

target sets the destination path. It can start with ~ for the project root, or with a placeholder that resolves through the user's components.json aliases: @components/, @ui/, @lib/ or @hooks/.

{
  "path": "registry/default/example/button.tsx",
  "type": "registry:ui",
  "target": "@ui/button.tsx"
}

CSS, env vars and install messages

Items can also add css rules (such as @utility, @keyframes or @layer base blocks), example envVars written to .env.local without overwriting existing values, and a docs string the CLI prints after install. Keep envVars to development or placeholder values.

Step 4: Run shadcn build

npx shadcn@latest build

By default the command reads ./registry.json and writes one JSON file per item to public/r, so hello-world becomes public/r/hello-world.json. Change the destination with --output:

npx shadcn@latest build --output ./public/registry

Add it as a script so it runs before every deploy:

{
  "scripts": {
    "registry:build": "shadcn build"
  }
}

Step 5: Test locally

Start your dev server and install from it exactly as users will:

npx shadcn@latest list http://localhost:3000/r/registry.json
npx shadcn@latest add http://localhost:3000/r/hello-world.json

Test in a fresh project with its own components.json, so you catch missing registryDependencies or wrong targets.

Step 6: Host the registry

The output is static JSON, so any static host works: Vercel, Netlify, Cloudflare Pages, GitHub Pages or an S3 bucket. If you build the registry inside a Next.js docs site, the files in public/r are served automatically. For dynamic needs, such as per-user access, the docs describe serving items from route handlers using the shadcn/registry loaders.

Once deployed, users can add your namespace to their components.json:

{
  "registries": {
    "@acme": "https://acme.com/r/{name}.json"
  }
}

Hosting on GitHub instead

A public GitHub repo with a valid registry.json at its root is already installable through owner/repo/item addresses, with optional #ref pinning. This suits internal conventions, rules files and small utility collections that do not need a website.

Private registries

For paid or internal registries, require a token on your server and tell users to configure the registry with an Authorization or API key header read from an environment variable. Serve over HTTPS, rate-limit requests, and return a clear error message, since the CLI shows the server's message on 401 and 403 responses.

Step 7: Get listed in the official directory

Listing in the shadcn registry directory means users can type @yourname/item with no setup, because the CLI adds your registry to their components.json automatically. The requirements are:

  • The registry is open source and publicly accessible
  • It is valid JSON that follows the registry schema
  • It is flat: /registry.json and /component-name.json files sit at the root, with no nested items
  • File entries in registry.json do not include a content property

To submit, add your entry to apps/v4/registry/directory.json in the shadcn-ui/ui repository, run pnpm validate:registries, and open a pull request. Each entry has a name (your namespace), homepage, url template, description and a logo. After the PR is merged, the registry is live immediately.

If you want your registry in front of more developers, you can also submit it to the component library or block library categories here. Listings such as dashboardcn and Magic UI are good references for how public registries document their install commands.

FAQ

Do I need Next.js to host a registry?

No. The build output is plain JSON, and the items you publish can target any framework. Next.js is common only because many registries live inside a docs site.

Can I include the file contents in registry.json?

The build step embeds file contents into each generated item JSON. The root registry.json should only reference paths; the directory requirements explicitly reject content properties there.

How do users get updates to my components?

They run shadcn add again for the item, review the change with --diff, and accept or reject the overwrite. There is no automatic update, since the code lives in their project.

Can my items depend on official shadcn components?

Yes. List them by plain name in registryDependencies, such as button or card, or with the @shadcn/ namespace. The CLI installs any that are missing from the user's project before installing your item.