Generate Registry
Automation script to generate the registry.json file for a shadcn/ui registry.
Installation
npx oward-ui add generate-registryOverview
The generate-registry script is a Node.js automation tool that generates and maintains the registry.json file for a shadcn/ui registry. It automatically analyzes the structure of your components, utilities, and styles to create a registry compliant with the official shadcn/ui schema.
- Automatic detection of available types (ui, lib, style, item, etc.)
- Dependency extraction from ES6 and CommonJS imports
- Complex structure support with subfolders and multiple files
Node.js required
The script requires Node.js 14+ to work correctly.
Project structure
The script expects a standard project structure for a shadcn/ui registry:
your-project/
├── registry.json # Automatically generated file
└── registry/ # Source folder for components
├── ui/ # UI components
├── lib/ # Utilities and hooks
├── style/ # Styles and tokens
└── item/ # Complex items (blocks)Usage
Basic command
Run the script from the root directory of your registry:
node scripts/generate-registryThe script will:
- Scan the
./registry/folder to detect available types - For each type, analyze files and extract metadata
- Automatically generate registry entries with their dependencies
- Save the
registry.jsonfile
CLI options
The script accepts several options to customize its behavior:
| Option | Alias | Description | Default value |
|---|---|---|---|
--cwd <path> | -c | Base path of the project | Current directory |
--output <path> | -o | Path to the registry.json file | <path>/registry.json |
--path <path> | -p | Path to the components folder | <path>/registry |
--help | -h | Display help | - |
Usage examples
# Run from the current directory
node scripts/generate-registry
# With a specific path
node scripts/generate-registry --path /path/to/project
# With exit code check
node scripts/generate-registry || exit 1Types
The script automatically detects the types of components available in your registry. Each type corresponds to a category of files with a specific role in the shadcn/ui registry.
| Type | Folder | Default target | Description |
|---|---|---|---|
registry:ui | ui/ | components/ui/ | UI components and single-file primitives |
registry:component | component/ | components/ | Simple components |
registry:block | block/ | components/blocks/ | Complex multi-file components |
registry:hook | hook/ | hooks/ | React hooks |
registry:lib | lib/ | lib/ | Utility libraries and helpers |
registry:page | page/ | app/ | Page components or routes |
registry:style | style/ | styles/ | Style files (CSS, SCSS, LESS) |
registry:theme | theme/ | themes/ | Theme configurations |
registry:item | item/ | lib/ | Universal items (supports all file types and multi-file) |
registry:file | file/ | (manual definition) | Miscellaneous files |
Ignored folders (shadcn internal)
Some types are specific to the official shadcn registry and are automatically ignored by the script:
| Folder | Reason |
|---|---|
base/ | UI provider configuration (Radix UI, Base UI) - shadcn specific |
font/ | Google Fonts configuration - shadcn specific |
These folders, if they exist in your registry, will be ignored during generation.
Official documentation
For more information on registry types, see the official shadcn/ui documentation.
Dependency extraction
The script automatically extracts npm dependencies from your imports. It supports several syntaxes:
// Simple import
import { Button } from "lucide-react";
// Type import
import type { ButtonProps } from "lucide-react";
// Import all
import \* as React from "react";Excluded modules
Node.js built-in modules (fs, path, etc.) and relative imports are automatically excluded from registry dependencies.
Item metadata
The script automatically extracts metadata from items (components, hooks, utilities) to enrich the registry. This metadata can be defined via JSDoc directives or via the meta-registry.json file (supported for both multi-file and single-file items).
JSDoc directives
JSDoc directives are annotations in source code comments.
| Directive | Description | meta-registry.json |
|---|---|---|
@description | Component or utility description | ✔︎ |
@author | Author (format: "Name <[email protected]>") | ✔︎ |
@docs | Documentation/message displayed during installation | ✔︎ |
@packages | npm dependencies with versions | ✔︎ |
@registry-dependencies | Dependencies on other registry items | ✔︎ |
@target | Custom destination path in the project | ✔︎ |
@registry-ignore | Excludes the file from generation |
meta-registry.json only properties
Additional properties available only via the meta-registry.json file.
| Property | Description |
|---|---|
tailwind | Tailwind configuration (colors, keyframes, etc.) |
cssVars | CSS variables (theme, light, dark) |
css | Additional CSS rules (@keyframes, @layer, etc.) |
meta-registry.json file
The meta-registry.json file centralizes an item's metadata and takes priority over JSDoc directives. Three structures are supported:
| Structure | Use case | File location |
|---|---|---|
| Multi-file folder | Complex items with multiple files | registry/item/dashboard/meta-registry.json |
| Single-file folder | Simple item organized in a folder | registry/ui/button/meta-registry.json |
| Adjacent file | Simple item without dedicated folder | registry/ui/button.meta-registry.json |
Structure examples:
# Multi-file folder
registry/item/dashboard/
├── dashboard.tsx
├── utils.ts
└── meta-registry.json
# Single-file folder
registry/ui/button/
├── button.tsx
└── meta-registry.json
# Adjacent file (no folder)
registry/ui/
├── input.tsx
└── input.meta-registry.jsonBeware of files at type root
A meta-registry.json placed directly at a type's root (e.g.,
registry/ui/meta-registry.json) will be ignored for adjacent single-file
items. This file only affects items organized in subfolders.
File structure:
{
"description": "Dashboard component with sidebar and charts",
"author": "Your Name <[email protected]>",
"target": "components/blocks",
"dependencies": {
"tailwind-merge": "^3.4.0",
"recharts": "^2.10.0"
},
"registryDependencies": [
"@namespace/button",
"@namespace/card",
"@namespace/chart"
]
}Complete structure with styling (tailwind, cssVars, css):
{
"description": "Sidebar component with custom theme",
"tailwind": {
"config": {
"theme": {
"extend": {
"colors": {
"sidebar": {
"DEFAULT": "hsl(var(--sidebar-background))",
"foreground": "hsl(var(--sidebar-foreground))"
}
}
}
}
}
},
"cssVars": {
"theme": {
"--animate-wiggle": "wiggle 1s ease-in-out infinite"
},
"light": {
"sidebar-background": "0 0% 98%",
"sidebar-foreground": "240 5.3% 26.1%"
},
"dark": {
"sidebar-background": "240 5.9% 10%",
"sidebar-foreground": "240 4.8% 95.9%"
}
},
"css": {
"@keyframes wiggle": {
"0%, 100%": { "transform": "rotate(-3deg)" },
"50%": { "transform": "rotate(3deg)" }
}
}
}Tailwind v4
The tailwind property is deprecated for Tailwind v4 projects.
Use cssVars.theme instead to define theme variables.
@author
Specifies the author of the component or utility.
/**
* @author Geoffrey From Oward <[email protected]>
*/
export function Button() {
return <button>Click me</button>;
}@description
Defines a clear description of the component or utility.
/**
* @description A customizable button with variant support
* @author Your Name <[email protected]>
*/
export function Button() {
return <button>Click me</button>;
}@docs
Displays a message or custom documentation during component installation via shadcn CLI. Useful for indicating prerequisites, required configuration, or setup instructions.
/**
* @docs To get an OPENAI_API_KEY, create an account at https://platform.openai.com
* @description AI chat component
*/
export function AIChat() {
return <div>AI Chat</div>;
}Use cases: Configuration instructions (environment variables, API keys), system prerequisites, important notes about component usage.
@packages
Specifies npm dependency versions. By default, dependencies are automatically extracted without version. Use this directive to force a specific version.
Two JSDoc syntaxes are supported: multi-line or inline (multiple packages on one line).
// Multi-line syntax
/**
* @packages tailwind-merge@^3.4.0
* @packages lucide-react@^0.400.0
* @packages clsx@^2.0.0
*/
export function Card() {
return <div>Card</div>;
}
// Inline syntax
/**
* @packages tailwind-merge@^3.4.0 lucide-react@^0.400.0 clsx@^2.0.0
*/
export function Alert() {
return <div>Alert</div>;
}Both syntaxes can be mixed. You only need to specify dependencies requiring a specific version. Others will be auto-detected without version.
@registry-dependencies
Declares that your component depends on other registry items. During installation, shadcn CLI will automatically install these dependencies.
Two JSDoc syntaxes are supported: multi-line or inline (multiple dependencies on one line).
// Multi-line syntax
/**
* @registry-dependencies https://my-registry.com/r/button.json
* @registry-dependencies @oward/icon
*/
export function IconButton() {
return <Button><Icon /></Button>;
}
// Inline syntax
/**
* @registry-dependencies @oward/button @oward/input @oward/select @oward/label
*/
export function Form() {
return <form>...</form>;
}Both syntaxes can be mixed. Dependencies can be scoped packages
(@acme/button), or URLs to external registries.
@target
Customizes the destination path in the user's project. By default, the path is automatically generated according to the type (components/ui/, lib/, hooks/, etc.).
/**
* @target components/custom
*/
export function CustomButton() {
// Will be installed in: components/custom/custom-button.tsx
return <button>Custom</button>;
}Multi-file example:
registry/item/dashboard/
├── dashboard.tsx
├── utils.ts
└── meta-registry.json → {"target": "components/blocks"}
Result after installation:
components/blocks/
├── dashboard.tsx
└── utils.tsThe @target annotation specifies only the destination folder. The
filename is automatically preserved.
Use @target only if you need a different location than the automatically
generated one. In most cases, automatic generation is sufficient.
@registry-ignore
Excludes a file from registry generation. Useful for base files (like cn()) that should not be installable via shadcn CLI.
This directive is only available as a JSDoc annotation. It cannot be used
in meta-registry.json as it applies at the file level.
// @registry-ignore
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}Usage example: The lib/utils.ts file containing the cn() function
should be ignored as it is automatically added during npx shadcn@latest init. All shadcn components assume this function already exists.
Script output
The script generates a registry.json file compliant with the shadcn/ui schema:
{
"name": "my-registry",
"items": [
{
"name": "button",
"type": "registry:ui",
"title": "Button",
"description": "A customizable button with variant and size support",
"author": "Your Name <[email protected]>",
"dependencies": ["class-variance-authority"],
"registryDependencies": ["utils"],
"files": [
{
"path": "registry/ui/button.tsx",
"type": "registry:ui",
"target": "components/ui/button.tsx"
}
]
}
]
}