# How the shadcn Build Process Works: Configuration, Output, and Registry Generation

> Explore the shadcn build process: learn how tsup compiles code into ES modules and generates registry JSON files for component installation.

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

---

**The shadcn build process compiles the CLI and core utilities into a minified ES-module bundle using tsup, while a separate registry build command generates static JSON files that power the component installation workflow.**

The `shadcn-ui/ui` repository is a monorepo that packages the shadcn CLI and its registry system. Understanding the shadcn build process is essential for contributors who need to modify the CLI or maintain a custom component registry. This article breaks down the bundler configuration, monorepo orchestration, and registry generation pipeline.

## shadcn Build Output Configuration

The core build configuration lives in [`packages/shadcn/tsup.config.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/tsup.config.ts) and uses **tsup**, a fast TypeScript bundler built on esbuild.

### tsup Bundler Settings

The configuration defines a strict ES-module output with aggressive optimizations:

```typescript
// packages/shadcn/tsup.config.ts
import { defineConfig } from "tsup"

export default defineConfig({
  clean: true,           // Removes dist/ before building
  dts: true,             // Generates .d.ts type declarations
  entry: [
    "src/index.ts",      // CLI entry point
    "src/registry/**/*.ts",
    "src/utils/**/*.ts",
    // ... other public APIs
  ],
  format: ["esm"],       // Only ES modules
  sourcemap: true,       // Debug symbols
  minify: true,          // Minified output
  target: "esnext",      // Latest JavaScript features
  outDir: "dist",        // Output directory
  treeshake: true,        // Remove unused code
  onSuccess: "cp src/tailwind.css dist/tailwind.css"
})

```

The `onSuccess` hook copies [`src/tailwind.css`](https://github.com/shadcn-ui/ui/blob/main/src/tailwind.css) into the `dist` folder, ensuring the CLI can access the base Tailwind styles when initializing new projects.

### Output Directory Structure

After running the build, `packages/shadcn/dist/` contains:

- [`index.js`](https://github.com/shadcn-ui/ui/blob/main/index.js) – The CLI entry point (shebang included for `npx` execution)
- `registry/`, `schema/`, `utils/`, `icons/` – Sub-paths for modular imports
- [`tailwind.css`](https://github.com/shadcn-ui/ui/blob/main/tailwind.css) – Static asset for project initialization
- `*.d.ts` – Bundled type definitions for TypeScript consumers

## Monorepo Build Orchestration with Turbo

The `shadcn-ui/ui` repository uses **Turborepo** to coordinate builds across packages.

### Root-Level Build Scripts

The root [`package.json`](https://github.com/shadcn-ui/ui/blob/main/package.json) defines a Turbo pipeline:

```json
{
  "scripts": {
    "build": "turbo run build"
  }
}

```

Running `pnpm run build` (or `npm run build`) triggers `turbo run build`, which walks the dependency graph and executes package builds in parallel where possible.

### Package-Specific Build Commands

For the `shadcn` package specifically, the build is invoked via:

```bash
pnpm shadcn:build            # alias for pnpm --filter=shadcn build

```

This executes the `build` script defined in [`packages/shadcn/package.json`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/package.json):

```json
{
  "scripts": {
    "build": "tsup"
  }
}

```

Other packages in the monorepo (such as the `v4` app) have their own build steps, but the core CLI output always lands in `packages/shadcn/dist`.

## shadcn Registry Build Process

Beyond the CLI bundle, shadcn provides a **registry build** command that generates static JSON files powering the component installation workflow.

### CLI Command Structure

The registry build logic lives in [`packages/shadcn/src/commands/registry/build.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/commands/registry/build.ts). The command is exposed through the CLI as:

```bash
pnpm shadcn registry:build

```

Or using the production binary:

```bash
pnpm shadcn:prod registry:build

```

The command accepts several options:
- `-o, --output` – Output directory (default: `./public/r`)
- `-c, --cwd` – Working directory
- `--verbose` – Detailed logging

### Registry Resolution and Validation

The build process follows a strict pipeline:

1. **Pre-flight validation** – Ensures [`registry.json`](https://github.com/shadcn-ui/ui/blob/main/registry.json) (or [`components.json`](https://github.com/shadcn-ui/ui/blob/main/components.json)) exists and loads project configuration.
2. **Schema validation** – Loads and validates [`registry.json`](https://github.com/shadcn-ui/ui/blob/main/registry.json) against a Zod schema.
3. **Item resolution** – Recursively walks each `registryItem.files`, resolving `import` statements and pulling referenced files and dependencies.
4. **Deduplication** – Removes duplicate file paths and dependencies per item.
5. **Content embedding** – Reads the source code of every resolved file from disk and stores it under `file.content`.

### JSON Generation and Output

After processing, the command:

1. Attaches a `$schema` URL for editor validation.
2. Validates each enriched item against `registryItemSchema`.
3. Writes one JSON file per registry item to the output directory (default `./public/r`).
4. Copies the master [`registry.json`](https://github.com/shadcn-ui/ui/blob/main/registry.json) into the output folder.
5. Optionally prints a summary of generated items when `--verbose` is enabled.

The resulting `./public/r` folder contains:
- [`registry.json`](https://github.com/shadcn-ui/ui/blob/main/registry.json) – The master index of all available components.
- Individual JSON files (e.g., [`button.json`](https://github.com/shadcn-ui/ui/blob/main/button.json), [`card.json`](https://github.com/shadcn-ui/ui/blob/main/card.json)) – Self-contained component definitions with embedded source code.

## Practical Build Examples

### Building the Component Library

To compile the shadcn CLI and utilities from the repository root:

```bash

# Build all packages using Turbo

pnpm run build

# Or build only the shadcn package

pnpm shadcn:build

```

The output lands in `packages/shadcn/dist/` and includes the CLI entry point, type definitions, and the [`tailwind.css`](https://github.com/shadcn-ui/ui/blob/main/tailwind.css) asset.

### Building the Registry JSON

To generate the static registry files for component distribution:

```bash

# Default output to ./public/r

pnpm shadcn registry:build

# Custom working directory and output

pnpm shadcn registry:build -c ./my-app -o ./my-app/public/registry

# With detailed logging

pnpm shadcn registry:build --verbose

```

The production CLI runs with `REGISTRY_URL=https://ui.shadcn.com/r`, serving the generated JSON files as static assets.

## Key Configuration Files

| File | Role |
|------|------|
| [`packages/shadcn/tsup.config.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/tsup.config.ts) | Defines how TypeScript source compiles into the `dist` folder using tsup. |
| [`packages/shadcn/package.json`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/package.json) | Contains the `build` script (`tsup`) and publish configuration. |
| [`packages/shadcn/src/commands/registry/build.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/commands/registry/build.ts) | Implements the CLI command that creates JSON registry output. |
| [`package.json`](https://github.com/shadcn-ui/ui/blob/main/package.json) (root) | Turbo monorepo orchestration; top-level `build` script runs all package builds. |
| [`turbo.json`](https://github.com/shadcn-ui/ui/blob/main/turbo.json) | Turbo configuration defining the task graph and build caching. |

## Summary

- **tsup configuration** in [`packages/shadcn/tsup.config.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/tsup.config.ts) controls the bundler settings, producing a minified ES-module output with type declarations in `dist/`.
- **Turborepo orchestration** coordinates builds across the monorepo via `turbo run build`, with the shadcn package building independently through `pnpm shadcn:build`.
- **Registry build command** (`shadcn registry:build`) generates static JSON files by resolving imports, deduplicating dependencies, and embedding source code into `public/r/`.
- **Output artifacts** include the CLI bundle ([`index.js`](https://github.com/shadcn-ui/ui/blob/main/index.js)), sub-modules for registry utilities, TypeScript declarations, and the [`tailwind.css`](https://github.com/shadcn-ui/ui/blob/main/tailwind.css) asset required for project initialization.

## Frequently Asked Questions

### What bundler does shadcn use for its build process?

The shadcn CLI and core utilities are bundled using **tsup**, a fast TypeScript bundler built on esbuild. The configuration in [`packages/shadcn/tsup.config.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/tsup.config.ts) specifies ES-module output, type declaration generation, minification, and tree-shaking to produce the final `dist/` artifacts.

### How does the shadcn registry build command work?

The `shadcn registry:build` command, implemented in [`packages/shadcn/src/commands/registry/build.ts`](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/commands/registry/build.ts), reads the project's [`registry.json`](https://github.com/shadcn-ui/ui/blob/main/registry.json), validates it against a Zod schema, recursively resolves all file imports for each registry item, deduplicates dependencies, embeds the source code content, and writes individual JSON files to the output directory (default `./public/r`).

### Where does the shadcn build output go?

The main CLI build outputs to `packages/shadcn/dist/` and includes [`index.js`](https://github.com/shadcn-ui/ui/blob/main/index.js) (the CLI entry point), modular sub-directories for registry and utility functions, bundled [`.d.ts`](https://github.com/shadcn-ui/ui/blob/main/.d.ts) type declarations, and a copied [`tailwind.css`](https://github.com/shadcn-ui/ui/blob/main/tailwind.css) file. The registry build outputs to `./public/r/` (configurable via `-o` flag) and contains the master [`registry.json`](https://github.com/shadcn-ui/ui/blob/main/registry.json) and individual component JSON files.

### Can I customize the output directory for the registry build?

Yes, the `shadcn registry:build` command accepts an `-o, --output` flag to specify a custom directory. For example, `pnpm shadcn registry:build -o ./my-app/public/registry` directs the generated JSON files to that location instead of the default `./public/r`.