Capítulo 99 de 108
Full walkthrough for standing up a custom registry: define registry.json, add items, serve them (static build or dynamic route handlers), test with CLI commands, and publish for others to consume.
registry.json: The entry point at the registry root; contains name, homepage, and either a flat items array or include (composed from multiple nested registry.json files).include structure: Small registries put everything in one root registry.json; larger ones split by directory (components/ui/registry.json, hooks/registry.json) and compose via root include. Included files may omit name/homepage; only root needs them. With include, file paths are relative to the declaring registry.json, not the project root.npx shadcn build: Generates static registry JSON files (default public/r/[name].json); resolves include and flattens output (no include in generated JSON). --output changes the target dir.shadcn/registry: Install shadcn as a runtime dep; use loadRegistry() (serves the catalog) and loadRegistryItem(name) (serves one item, throws RegistryItemNotFoundError on 404) in route handlers — both resolve include at request time without needing shadcn build.User-Agent: shadcn and Accept: application/vnd.shadcn.v1+json, application/json;q=0.9; a server can inspect these to serve JSON to the CLI/MCP while serving HTML/docs to browsers from the same root URL — enables "branded registry URLs" like shadcn add https://ui.example.com.list/search/view/add all accept either a direct catalog/item URL, or a configured @namespace (added via npx shadcn registry add @acme=URL_TEMPLATE).{
"$schema": "https://ui.shadcn.com/schema/registry.json",
"name": "acme",
"homepage": "https://acme.com",
"items": [
{
"name": "button",
"type": "registry:ui",
"title": "Button",
"description": "A simple button component.",
"files": [{ "path": "components/ui/button.tsx", "type": "registry:ui" }]
}
]
}
registry.json com um item.import { loadRegistryItem, RegistryItemNotFoundError } from "shadcn/registry"
export async function GET(_request: Request, context: { params: Promise<{ name: string }> }) {
const { name } = await context.params
try {
const item = await loadRegistryItem(name)
return Response.json(item)
} catch (error) {
if (error instanceof RegistryItemNotFoundError) {
return Response.json({ error: `Registry item "${name}" was not found.` }, { status: 404 })
}
return Response.json({ error: "Failed to load registry item." }, { status: 500 })
}
}
loadRegistryItem, sem precisar rodar shadcn build.| CLI test command | Purpose | URL form | Namespace form |
|---|---|---|---|
list | discover catalog items | list <catalog-url> | list @acme |
search --query | search catalog | search <catalog-url> --query button | search @acme --query button |
view | inspect one item | view <item-url> | view @acme/button |
add | install one item | add <item-url> | add @acme/button |
path conventions between single-file and include registries: with include, paths are relative to the declaring file, not project root — a common source of broken builds.registryDependencies for cross-item deps: components referencing other registry items must declare it, or the CLI won't resolve/install them.title/description: recommended so LLMs (and MCP) can understand the component's purpose.@/registry path: registry items should import via @/registry/default/hello-world/hello-world, not relative paths, to survive relocation.registry-template GitHub repo if building a new registry from scratch, or add registry.json to an existing public repo to make it GitHub-installable (see GitHub registries doc).path and type; the type determines default install location, and target can override it (required for registry:page/registry:file).shadcn build) is simplest for stable content; dynamic route handlers via shadcn/registry loaders suit registries with request-time logic (auth, personalization).@namespace shortcuts without pasting a URL, submit to the official Registry Index (open-source, publicly accessible registries only).registry/[STYLE]/[NAME], organized internally into components, hooks, lib.registry.json referenced throughout this guide.files[].type.registry.json at the root that this guide sets up.