}>
  Patterns that come up in real consumers, beyond field-by-field reference material.

## Recipe 1: Docs-site registry

This is the common shape for a docs app that needs:

* `index.json`
* per-item component payloads
* a generated component index file
* theme and color outputs

```ts
import {
  bannerExtension,
  colorsExtension,
  componentIndexExtension,
  componentsExtension,
  defineConfig,
  indexBuildExtension,
  validateExtension,
} from '@gentleduck/registry-build'

export default defineConfig({
  sources: {
    'registry:ui': {
      path: '../../packages/registry-ui/src',
      packageName: '@example/registry-ui',
      referencePath: '/registry-ui/src',
    },
    'registry:example': {
      path: '../../packages/registry-examples/src',
      packageName: '@example/registry-examples',
      referencePath: '/registry-examples/src',
      indexStrategy: 'file',
    },
  },
  registries: {
    uis: [...],
    examples: [...],
  },
  output: {
    dir: '.',
  },
  targetPaths: {
    'registry:ui': 'components/ui',
    'registry:example': 'components',
  },
  extensions: [
    bannerExtension({ name: 'My Docs' }),
    validateExtension(),
    indexBuildExtension(),
    componentsExtension(),
    componentIndexExtension({
      framework: 'nextjs',
    }),
    colorsExtension(),
  ],
})
```

***

## Recipe 2: Arch-style package repository

This pattern treats `registry-build` as a generic build core plus a custom extension. The core UI phases are disabled, and the custom extension emits repository metadata, package-file manifests, and search artifacts.

```ts
import { defineConfig } from '@gentleduck/registry-build'
import { archRepositoryExtension } from './arch-repository.extension'

export default defineConfig({
  collections: {
    packages: {
      data: './data/packages.json',
      metadata: {
        repoOrder: ['core', 'extra'],
      },
      sources: {
        pkgbuilds: {
          glob: '**/PKGBUILD',
          path: './pkgbuilds',
        },
      },
    },
  },
  extensions: [
    archRepositoryExtension({
      collection: 'packages',
    }),
  ],
  output: {
    dir: './dist',
  },
})
```

This is the direction for non-UI consumers: collections plus extensions, not empty `componentIndex` or `themes` objects.

See the in-repo example in `packages/registry-build/examples/arch-package-index`.

If you want the full guided build, continue to [Course](/duck-registry-build/course) and [Arch Package Index](/duck-registry-build/course-arch-package-index).

***

## Recipe 3: Custom manifest extension

If another tool needs a derived manifest after the registry build finishes, expose it through an `afterBuild` extension:

```ts
{
  name: 'manifest',
  stage: 'afterBuild',
  async run(api) {
    const manifest = {
      outputs: api.listOutputs().map((output) => output.name),
      itemCount: (api.getArtifact('index') as Array<unknown> | undefined)?.length ?? 0,
    }

    // write file, register output, set artifact
  },
}
```

Use this pattern instead of patching the core runner.

***

## Recipe 4: External static data files

Use root config file paths when colors/themes or registry entries live in static JSON files:

```ts
export default defineConfig({
  registrySource: './data/registry-entries.json',
  colors: {
    data: './data/colors.json',
  },
  themes: {
    data: './data/themes.json',
  },
  output: {
    dir: '.',
  },
})
```

This keeps static data portable and avoids importing giant objects into every consumer config file manually.

***

## Recipe 5: Extend a base config

File-based composition:

```ts
export default defineConfig({
  extends: ['./registry-build.base.ts', './registry-build.theme.ts'],
  output: {
    dir: '.',
  },
})
```

Code-based composition:

```ts
import { defineConfig, mergeRegistryBuildConfigs } from '@gentleduck/registry-build'
import { base } from './registry-build.base'
import { theme } from './registry-build.theme'

export default defineConfig(mergeRegistryBuildConfigs(base, theme))
```

Use file-based composition when the config should stay mostly declarative. Use code-based composition when you need parameterized factories.

***

## Recipe 6: Custom framework component index

If the built-in framework adapters are not enough, provide a custom generator:

```ts
componentIndexExtension({
  generator(items) {
    return [
      '// custom generated file',
      `export const items = ${JSON.stringify(items, null, 2)}`,
    ].join('\n')
  },
})
```

That keeps the rest of the build intact while taking full control over the generated file.

***

## Recipe 7: Fast local rebuild loop

Use split scripts so the raw CLI path remains available:

```json
{
  "scripts": {
    "build:reg": "bun run build:reg:cli && bun run format:reg",
    "build:reg:cli": "registry-build build",
    "format:reg": "bunx biome format --write ./__ui_registry__/index.tsx"
  }
}
```

Then for targeted local updates:

```bash
bun run build:reg:cli - --changed-only --changed ../../packages/registry-ui/src/button/button.tsx
```

***

## Rule of thumb

}>
  If you can describe it as static data, put it in config. If you need to compute or emit something after the registry exists, write an extension. If you need to reuse a config shape across consumers, extract a preset or config factory.