Skip to main content

Configuration

Full registry-build config reference with a generic-first shape, collection docs, and legacy compatibility notes.

Minimal generic shape

import { defineConfig } from '@gentleduck/registry-build'
 
export default defineConfig({
  extends: ['./registry-build.base.ts'],
  collections: {},
  output: {
    dir: './dist',
  },
  performance: {},
  branding: {},
  extensions: [],
})
import { defineConfig } from '@gentleduck/registry-build'
 
export default defineConfig({
  extends: ['./registry-build.base.ts'],
  collections: {},
  output: {
    dir: './dist',
  },
  performance: {},
  branding: {},
  extensions: [],
})

Generic-first reference

collections

collections is the generic input surface for non-UI builds.

Each collection can provide:

FieldTypePurpose
dataunknown | stringInline data or a file path to load
metadataRecord<string, unknown>Arbitrary static metadata for extensions
sourcesRecord<string, RegistryBuildSource>Named source trees related to the collection
collections: {
  packages: {
    data: './data/packages.json',
    metadata: {
      repoOrder: ['core', 'extra', 'community'],
    },
    sources: {
      pkgbuilds: {
        glob: '**/PKGBUILD',
        path: './pkgbuilds',
        referencePath: '/pkgbuilds',
      },
    },
  },
}
collections: {
  packages: {
    data: './data/packages.json',
    metadata: {
      repoOrder: ['core', 'extra', 'community'],
    },
    sources: {
      pkgbuilds: {
        glob: '**/PKGBUILD',
        path: './pkgbuilds',
        referencePath: '/pkgbuilds',
      },
    },
  },
}

Use collections when you are building a package index or repository catalog, when you want extensions to read arbitrary data without pretending it is a UI component registry, and when you want a small generic config with minimal domain assumptions.

output

output.dir is required after defaults and extends are resolved.

FieldDefault
dirrequired
registryDirpublic/r
componentIndexDir__ui_registry__
componentIndexFileindex.tsx
componentsDircomponents
colorsDircolors
themesDirthemes
themesCssFilethemes.css
output: {
  dir: './dist',
}
output: {
  dir: './dist',
}

Even in a generic build, the cache still lives under <output.dir>/.registry-build/ by default.

performance

Performance settings control incremental behavior.

FieldDefaultPurpose
cacheDir.registry-buildCache directory under output.dir
incrementaltrueEnable file-hash cache and phase reuse
parallelismmin(cpuCount, 8)Bound concurrent discovery and generation work
performance: {
  cacheDir: '.registry-build',
  incremental: true,
  parallelism: 6,
}
performance: {
  cacheDir: '.registry-build',
  incremental: true,
  parallelism: 6,
}
extensions

Extensions are the primary mechanism for adding behavior to the builder. The runner is entirely extension-driven — all processing (index-build, components, colors, component-index, validation, banners) is performed by extensions.

For UI registries, either use uiRegistryPreset() to bundle the standard extensions, or register them individually for full control:

import {
  bannerExtension,
  colorsExtension,
  componentIndexExtension,
  componentsExtension,
  defineConfig,
  indexBuildExtension,
  validateExtension,
} from '@gentleduck/registry-build'
 
export default defineConfig({
  extensions: [
    bannerExtension({ name: 'My Registry' }),
    validateExtension(),
    indexBuildExtension(),
    componentsExtension(),
    componentIndexExtension({ framework: 'nextjs' }),
    colorsExtension(),
  ],
  output: { dir: './dist' },
  // ...
})
import {
  bannerExtension,
  colorsExtension,
  componentIndexExtension,
  componentsExtension,
  defineConfig,
  indexBuildExtension,
  validateExtension,
} from '@gentleduck/registry-build'
 
export default defineConfig({
  extensions: [
    bannerExtension({ name: 'My Registry' }),
    validateExtension(),
    indexBuildExtension(),
    componentsExtension(),
    componentIndexExtension({ framework: 'nextjs' }),
    colorsExtension(),
  ],
  output: { dir: './dist' },
  // ...
})

For custom builds, register your own extensions:

extensions: [
  archRepositoryExtension({
    collection: 'packages',
  }),
]
extensions: [
  archRepositoryExtension({
    collection: 'packages',
  }),
]

The recommended pattern is to keep static data in config, let extensions read collections and existing artifacts, and let extensions register outputs explicitly.

branding

branding is lightweight metadata for CLI- or extension-facing presentation.

FieldTypeDefault
namestring'@gentleduck/registry-build'
fontstring'ANSI Shadow'
branding: {
  name: 'Acme Registry',
  font: 'ANSI Shadow',
}
branding: {
  name: 'Acme Registry',
  font: 'ANSI Shadow',
}

Treat this as presentation metadata, not as core build logic.

extends and mergeRegistryBuildConfigs

Use extends for file-based composition and mergeRegistryBuildConfigs() for code-driven composition.

extends is path-aware. Collection data files resolve relative to the file that declared them, collection source paths resolve relative to the file that declared them, source paths and external data files from compatibility fields follow the same rule, and maps and arrays are merged where appropriate.

export default defineConfig({
  extends: ['./registry-build.base.ts', './registry-build.arch.ts'],
  output: {
    dir: './dist',
  },
})
export default defineConfig({
  extends: ['./registry-build.base.ts', './registry-build.arch.ts'],
  output: {
    dir: './dist',
  },
})
import { defineConfig, mergeRegistryBuildConfigs } from '@gentleduck/registry-build'
import { baseConfig } from './registry-build.base'
import { archConfig } from './registry-build.arch'
 
export default defineConfig(mergeRegistryBuildConfigs(baseConfig, archConfig))
import { defineConfig, mergeRegistryBuildConfigs } from '@gentleduck/registry-build'
import { baseConfig } from './registry-build.base'
import { archConfig } from './registry-build.arch'
 
export default defineConfig(mergeRegistryBuildConfigs(baseConfig, archConfig))

UI compatibility reference

sources

sources maps each UI registry item type to a source directory definition.

FieldTypePurpose
pathstringFilesystem path relative to the config file
packageNamestringPackage base used for generated import paths
globstringDiscovery pattern, default **/*.{ts,tsx}
ignorestring[]Ignore globs for discovery, default ['**/__test__/**', '**/*.test.*', '**/*.spec.*']
indexStrategy'item' | 'file'Emit one index record per registry item or per discovered file
referencePathstringStable logical path stored in generated metadata
sources: {
  'registry:ui': {
    path: '../../packages/registry-ui/src',
    packageName: '@example/registry-ui',
    referencePath: '/registry-ui/src',
  },
  'registry:example': {
    path: '../../packages/registry-examples/src',
    indexStrategy: 'file',
    referencePath: '/registry-examples/src',
  },
}
sources: {
  'registry:ui': {
    path: '../../packages/registry-ui/src',
    packageName: '@example/registry-ui',
    referencePath: '/registry-ui/src',
  },
  'registry:example': {
    path: '../../packages/registry-examples/src',
    indexStrategy: 'file',
    referencePath: '/registry-examples/src',
  },
}

UI item types are validated as registry:${string}.

registries and registrySource

registries is the structured metadata that describes UI registry items. Categories are consumer-defined keys such as uis, examples, or blocks.

registrySource controls where those entries come from. Use 'inline' to read the registries object directly, or use a file path to load external JSON or TS data and merge it with inline entries.

registrySource: 'inline',
registries: {
  uis: [
    {
      name: 'button',
      root_folder: 'button',
      type: 'registry:ui',
    },
  ],
}
registrySource: 'inline',
registries: {
  uis: [
    {
      name: 'button',
      root_folder: 'button',
      type: 'registry:ui',
    },
  ],
}

Each entry can include metadata such as dependencies, registryDependencies, files, description, categories, tailwind, and cssVars.

importMappings and targetPaths

Use contentRewrites when copied source files need import rewriting. Use packageMappings when generated component indexes should import from a package path that differs from the source declaration.

Use targetPaths to tell generated item files where they should land in consumer projects.

importMappings: {
  contentRewrites: [
    {
      pattern: '@old/pkg',
      replacement: '@new/pkg',
    },
  ],
  packageMappings: {
    'registry:ui': '@example/registry-ui',
    'registry:example': '@example/registry-examples',
  },
},
targetPaths: {
  'registry:ui': 'components/ui',
  'registry:example': 'components',
}
importMappings: {
  contentRewrites: [
    {
      pattern: '@old/pkg',
      replacement: '@new/pkg',
    },
  ],
  packageMappings: {
    'registry:ui': '@example/registry-ui',
    'registry:example': '@example/registry-examples',
  },
},
targetPaths: {
  'registry:ui': 'components/ui',
  'registry:example': 'components',
}
componentIndex

This config shapes the generated component import index used by componentIndexExtension().

FieldPurpose
frameworkSelect built-in adapter: nextjs, vite, or custom
headerOverride generated file header
excludeTypesSkip registry item types from the component index
ssrFramework-specific SSR hint
generatorFull custom generator function
componentIndex: {
  framework: 'nextjs',
  excludeTypes: ['registry:ui', 'registry:hook'],
  ssr: false,
}
componentIndex: {
  framework: 'nextjs',
  excludeTypes: ['registry:ui', 'registry:hook'],
  ssr: false,
}

If generator is set, it takes over file generation entirely.

colors, themes, and cssTemplates

These fields feed the colors/themes extension layer.

colors.data and themes.data can be inline objects or file paths when they are declared at the root config level.

themes also controls cssVarKeys, names, and defaultRadius.

cssTemplates lets consumers override the generated base CSS strings.

colors: {
  data: './data/colors.json',
},
themes: {
  data: './data/themes.json',
  names: ['zinc', 'stone'],
  cssVarKeys: ['background', 'foreground'],
  defaultRadius: '0.5rem',
},
cssTemplates: {
  baseStyles: '@tailwind base;\\n@tailwind components;\\n@tailwind utilities;',
  baseLayerRules: '@layer base { ... }',
}
colors: {
  data: './data/colors.json',
},
themes: {
  data: './data/themes.json',
  names: ['zinc', 'stone'],
  cssVarKeys: ['background', 'foreground'],
  defaultRadius: '0.5rem',
},
cssTemplates: {
  baseStyles: '@tailwind base;\\n@tailwind components;\\n@tailwind utilities;',
  baseLayerRules: '@layer base { ... }',
}
schema and stripVariables

schema.itemTypes declares the UI registry item type namespace you expect.

stripVariables removes named variables from copied source files before they are emitted into generated JSON payloads.

schema: {
  itemTypes: ['registry:ui', 'registry:example', 'registry:block'],
},
stripVariables: ['iframeHeight', 'description'],
schema: {
  itemTypes: ['registry:ui', 'registry:example', 'registry:block'],
},
stripVariables: ['iframeHeight', 'description'],

Rule of thumb