Core Configuration
defineConfig from @zod-to-form/core is the full, top-level configuration surface
for zod-to-form. It describes everything the schema walker and codegen pipeline
need: the component barrel, the form primitive wrappers, default generation
options, schema filters, the field-type registry, and global and per-schema
field mappings.
When to use
Use defineConfig when you want a single source of truth that both the
runtime (@zod-to-form/react) and the CLI (@zod-to-form/cli) can consume
to produce functionally identical forms. It is the configuration loaded from
z2f.config.ts by the CLI and can be imported directly by the runtime.
How it relates to defineComponentConfig:
defineComponentConfig(see Component Config) is the narrower surface. It only covers component mapping: thecomponentsmodule specifier,formPrimitives, and thefieldTypesregistry — the bits that decide which React component renders each field.defineConfigis the broader superset. It includes everything from the component-config surface plus the codegen-level controls:defaults,include,exclude,fields(global field mappings), andschemas(per-schema overrides).
If you only need to tell the runtime which components to use, reach for
defineComponentConfig. If you are driving the CLI, filtering schemas, or
hiding internal fields across a whole codebase, use defineConfig.
Installation and import
defineConfig ships from the core package:
import { defineConfig } from '@zod-to-form/core';
A typical project places the config in z2f.config.ts at the repo root so the
z2f CLI can auto-discover it:
// z2f.config.ts
import { defineConfig } from '@zod-to-form/core';
export default defineConfig({
components: '@/components/zod-form-components',
formPrimitives: { field: 'Field', label: 'FieldLabel', control: 'FieldControl' },
defaults: { mode: 'auto-save', ui: 'shadcn', overwrite: true, serverAction: false },
include: ['UserSchema'],
exclude: [],
fieldTypes: { Input: { component: 'Input' } },
fields: {},
schemas: {},
});
Full config shape
The top-level shape accepted by defineConfig:
import { defineConfig } from '@zod-to-form/core';
defineConfig({
components: string,
formPrimitives: { field: string; label: string; control: string },
defaults: {
mode: 'auto-save' | 'on-submit';
ui: string;
overwrite: boolean;
serverAction: boolean;
},
include: string[],
exclude: string[],
fieldTypes: Record<string, ComponentEntry>,
fields: Record<string, FieldConfig>,
schemas: Record<string, { fields: Record<string, FieldConfig> }>,
});
components
- Type:
string - Default: none — required.
- Purpose: Module specifier for the barrel file that exports every form
component referenced by
fieldTypesandformPrimitives. The codegen emits imports from exactly this path. - Example:
components: '@/components/zod-form-components';// Generated: import { Input, TypeSelector } from '@/components/zod-form-components';
formPrimitives
-
Type:
{ field: string; label: string; control: string } -
Default: none — required. Common values are
'Field','FieldLabel','FieldControl'. -
Purpose: Names of the wrapper components that surround every generated field. The
fieldwraps the whole row,labelwraps the label text, andcontrolwraps the input. -
Example:
formPrimitives: {field: 'Field',label: 'FieldLabel',control: 'FieldControl',}Renders as:
<Field><FieldLabel htmlFor="name">Name</FieldLabel><FieldControl><Input id="name" {...register('name')} /></FieldControl></Field>
defaults
- Type:
{ mode: 'auto-save' | 'on-submit'; ui: string; overwrite: boolean; serverAction: boolean } - Default: no defaults are applied unless the field is provided — the
source material shows
{ mode: 'auto-save', ui: 'shadcn', overwrite: true, serverAction: false }as the canonical starter value. - Purpose: Default generation options used by the CLI when a flag is not passed explicitly on the command line.
- Fields:
mode:'auto-save'wires awatch()subscription toonValueChangeon every field change;'on-submit'generates a standardonSubmithandler.ui: UI framework hint used byz2f initauto-detection heuristics (e.g.'shadcn').overwrite: whetherz2f generateoverwrites existing generated files.serverAction: wrap the form in a Next.js server action.
- Example:
defaults: {mode: 'auto-save',ui: 'shadcn',overwrite: true,serverAction: false,}
include
- Type:
string[] - Default: none — when omitted the source material does not document an explicit fallback; treat as "all exported schemas" until confirmed against the core package.
- Purpose: Allow-list of exported Zod schema
constnames to generate forms for. Names must match the exported identifier verbatim. - Example:
include: ['DataSchema', 'UserSchema'];
exclude
- Type:
string[] - Default:
[] - Purpose: Schemas to skip. Applied after
include, so it can strip a schema that was otherwise matched by the allow-list. - Example:
exclude: ['InternalSchema'];
fieldTypes
-
Type:
Record<string, ComponentEntry> -
Default: none — required to resolve any
fieldTypekeys used infieldsorschemas. -
Purpose: Registry of every custom component type that can be referenced by name from field mappings. Each entry points at a component exported from the
componentsbarrel. -
ComponentEntryshape:Property Type Description componentstringComponent name (must be exported from componentsbarrel).controlledboolean?Use the <Controller>pattern instead ofregister(). Required for components that do not acceptref(Select, Combobox, custom widgets).propMapRecord<string, string>?Remap RHF field props onto component-specific prop names, e.g. { onSelect: 'field.onChange', selectedValue: 'field.value' }. -
Example:
fieldTypes: {Input: { component: 'Input' },Textarea: { component: 'Textarea' },Select: { component: 'Select', controlled: true },TypeSelector: { component: 'TypeSelector', controlled: true },}
fields
-
Type:
Record<string, FieldConfig> -
Default:
{} -
Purpose: Global field mappings applied across every schema the generator touches. Keys are field paths using the path syntax documented below.
-
FieldConfigshape:type FieldConfig = {fieldType?: string; // Key from fieldTypes registryhidden?: boolean; // Exclude from generated output entirelyprops?: Record<string, unknown>; // Extra props passed to the componentorder?: number; // Rendering order within array item groups}; -
Path syntax:
Pattern Matches 'name'Top-level field 'typeCall.type'Nested object field 'attributes[].name'Field within array items 'attributes[].typeCall.type'Deep nested in array Always use
[]bracket notation for arrays — neveritems.0.field. -
Example:
fields: {parent: { fieldType: 'TypeSelector' },'attributes[].typeCall.type': { fieldType: 'TypeSelector' },'attributes[].card': { fieldType: 'CardinalitySelector' },definition: { fieldType: 'Textarea', props: { rows: 3 } },// Hide type discriminators and custom-rendered sections.$type: { hidden: true },'attributes[].$type': { hidden: true },annotations: { hidden: true },}
schemas
- Type:
Record<string, { fields: Record<string, FieldConfig> }> - Default:
{} - Purpose: Per-schema overrides keyed by the exported schema const name.
Entries take precedence over the global
fieldsblock for that schema only. Useorderto control rendering sequence inside array item groups. - Example:
schemas: {DataSchema: {fields: {'attributes[].name': { fieldType: 'Input', order: 1 },'attributes[].typeCall.type': { fieldType: 'TypeSelector', order: 2 },'attributes[].card': { fieldType: 'CardinalitySelector', order: 3 },'attributes[].override': { hidden: true },},},}
Examples
1. Basic config
Minimal config pointing at a component barrel and generating forms for a single schema:
import { defineConfig } from '@zod-to-form/core';
export default defineConfig({
components: '@/components/zod-form-components',
formPrimitives: {
field: 'Field',
label: 'FieldLabel',
control: 'FieldControl',
},
defaults: {
mode: 'on-submit',
ui: 'shadcn',
overwrite: true,
serverAction: false,
},
include: ['UserSchema'],
exclude: [],
fieldTypes: {
Input: { component: 'Input' },
Textarea: { component: 'Textarea' },
},
fields: {},
schemas: {},
});
2. With defaults and global hidden fields
Auto-save forms with a broader field-type registry and a set of globally hidden internal fields:
import { defineConfig } from '@zod-to-form/core';
export default defineConfig({
components: '@/components/zod-form-components',
formPrimitives: {
field: 'Field',
label: 'FieldLabel',
control: 'FieldControl',
},
defaults: {
mode: 'auto-save',
ui: 'shadcn',
overwrite: true,
serverAction: false,
},
include: ['DataSchema', 'ChoiceSchema'],
exclude: [],
fieldTypes: {
Input: { component: 'Input' },
Textarea: { component: 'Textarea' },
TypeSelector: { component: 'TypeSelector', controlled: true },
CardinalitySelector: { component: 'CardinalitySelector', controlled: true },
},
fields: {
'attributes[].typeCall.type': { fieldType: 'TypeSelector' },
'attributes[].card': { fieldType: 'CardinalitySelector' },
definition: { fieldType: 'Textarea', props: { rows: 3 } },
$type: { hidden: true },
'attributes[].$type': { hidden: true },
'attributes[].typeCall.$type': { hidden: true },
'attributes[].typeCall.arguments': { hidden: true },
annotations: { hidden: true },
conditions: { hidden: true },
},
schemas: {},
});
3. With per-schema overrides
Global mappings plus tailored overrides for two schemas. ChoiceSchema hides
the name field that is globally mapped to Input:
import { defineConfig } from '@zod-to-form/core';
export default defineConfig({
components: '@/components/zod-form-components',
formPrimitives: {
field: 'Field',
label: 'FieldLabel',
control: 'FieldControl',
},
defaults: {
mode: 'auto-save',
ui: 'shadcn',
overwrite: true,
serverAction: false,
},
include: ['DataSchema', 'ChoiceSchema'],
exclude: [],
fieldTypes: {
Input: { component: 'Input' },
Textarea: { component: 'Textarea' },
TypeSelector: { component: 'TypeSelector', controlled: true },
CardinalitySelector: { component: 'CardinalitySelector', controlled: true },
},
fields: {
'attributes[].name': { fieldType: 'Input' },
'attributes[].typeCall.type': { fieldType: 'TypeSelector' },
'attributes[].card': { fieldType: 'CardinalitySelector' },
$type: { hidden: true },
'attributes[].$type': { hidden: true },
},
schemas: {
DataSchema: {
fields: {
'attributes[].name': { fieldType: 'Input', order: 1 },
'attributes[].typeCall.type': { fieldType: 'TypeSelector', order: 2 },
'attributes[].card': { fieldType: 'CardinalitySelector', order: 3 },
'attributes[].definition': { fieldType: 'Textarea', props: { rows: 2 }, order: 4 },
'attributes[].override': { hidden: true },
},
},
ChoiceSchema: {
fields: {
'attributes[].name': { hidden: true },
'attributes[].typeCall.type': { fieldType: 'TypeSelector', order: 1 },
'attributes[].definition': { fieldType: 'Textarea', props: { rows: 2 }, order: 2 },
},
},
},
});
Resolution precedence
When the same field has multiple configurations, the highest-priority source wins. Based on the documented behaviour in the source skills:
- Per-schema overrides (
schemas[SchemaName].fields) — highest priority. Explicitly documented as taking precedence over globalfields. - Global
fields— applied across every generated schema. fieldTypesauto-detection / inferred defaults — used when no explicit field mapping exists.z2f initpopulates the registry using a known-controlled list plus source heuristics.- CLI flags — flags passed to
z2f generateoverride the correspondingdefaultsentries (for example--no-overwriteagainstdefaults.overwrite). Field-level mappings themselves are not overridable from the CLI. - Runtime metadata — when the config is consumed by the runtime
<ZodForm>, per-field metadata attached via Zod descriptions / registries at the schema level is resolved independently ofdefineConfigfield mappings. The source material does not define a single merge order acrossdefineConfigand runtime metadata; treat the two as complementary and prefer per-schema config for codegen concerns and schema metadata for per-field UI hints. (Type inferred — see source skill files for the authoritative order.)
Cross-links
- Component Config — the narrower component-mapping surface shared by the runtime and CLI.
- Runtime Rendering — rendering forms from schemas at runtime
with
<ZodForm>anduseZodForm. - CLI — the
z2f generatecodegen pipeline that consumes this configuration. - Examples — end-to-end snippets that combine schemas, configuration, and the runtime or CLI surface.