Registry authoring
How the shadcn registry is built and validated — including the CSS-encoding traps learned the hard way.
registry.json at the repo root is the manifest: one entry per component, plus
tokens (registry:theme) and cn (registry:lib).
npm run registry:build # shadcn build → public/r/*.jsonIt runs automatically before next build via the prebuild script, so every
deploy regenerates the JSON. public/r/ is gitignored and never committed,
which makes stale registry output structurally impossible.
CI
.github/workflows/registry.yml builds the registry on every PR and push to
main, then runs two checks:
scripts/check-registry.mjs— validates file paths, build output, self-referencing registry-dependency URLs,"use client"directives, and the no-next/*-imports guarantee.scripts/check-tokens-parity.mjs— fails whensrc/app/globals.cssorsrc/styles/brands/sc1m.cssdrift from thetokensitem inregistry.json.
The token maps are duplicated deliberately, in the exact JSON shape the shadcn
CLI can merge. Structural blocks — the popup-motion utility, the toast
keyframes, @custom-variant dark, the reduced-motion media queries — are
maintained by hand and sit outside the parity check's scope.
CSS encoding traps
The shadcn CLI's CSS merger (shadcn@4.x) is particular about how css and
cssVars are encoded. All three of these were found by crashing it:
Local verification
npm run registry:build
node scripts/check-registry.mjs
node scripts/check-tokens-parity.mjs