Skip to main content

Core Configuration

defineConfig() from @zod-to-form/core is the shared configuration surface for codegen-oriented workflows. Put it in z2f.config.ts when you want one place to define:

  • where generated components come from
  • default generation settings for CLI and Vite
  • field-path overrides
  • per-export schema behavior
  • reusable defaults for exported subschemas

When to Use

Use defineConfig() when you want the CLI and Vite plugin to consume the same z2f.config.ts. The runtime can also import pieces of it, but runtime-only component module binding still happens through componentConfig on <ZodForm>.

Installation and Import

import { defineConfig } from '@zod-to-form/core';

A typical project places the config at the repo root:

// z2f.config.ts
import { defineConfig } from '@zod-to-form/core';

export default defineConfig({
components: {
source: '@/components/ui',
preset: 'shadcn',
},
defaults: {
out: 'src/components',
overwrite: true,
mode: 'submit',
},
fields: {},
schemas: {},
});

Full Config Shape

defineConfig({
components: {
source: string,
preset?: 'shadcn' | 'html',
fieldTemplate?: string,
overrides?: Record<string, {
controlled?: boolean,
props?: Record<string, unknown>,
}>,
},
defaults?: {
mode?: 'submit' | 'auto-save',
ui?: 'shadcn' | 'html',
out?: string,
overwrite?: boolean,
serverAction?: boolean,
formProvider?: boolean,
optimization?: {
level?: 1 | 2 | 3,
},
},
types?: string[],
include?: string[],
exclude?: string[],
fields?: Record<string, FieldConfig>,
schemas?: Record<string, {
name?: string,
component?: string,
mode?: 'submit' | 'auto-save',
out?: string,
serverAction?: boolean,
fields?: Record<string, FieldConfig>,
}>,
});

components

components describes the module that generated code imports from, plus optional preset and per-component overrides.

components: {
source: '@/components/ui',
preset: 'shadcn',
}

components.source

Static import path used by generated code.

components.preset

Optional base mapping:

  • 'shadcn' for Radix/shadcn-oriented defaults
  • 'html' for plain HTML controls

components.overrides

Per-component defaults, especially for controlled components:

components: {
source: '@/components/ui',
overrides: {
Select: {
controlled: true,
props: {
onValueChange: 'field.onChange',
value: 'field.value',
},
},
},
}

defaults

defaults contains generation fallbacks shared by CLI and Vite:

defaults: {
out: 'src/components',
overwrite: true,
mode: 'submit',
ui: 'shadcn',
serverAction: false,
optimization: {
level: 2,
},
}
FieldMeaning
modesubmit or auto-save
uiUI hint / preset selection
outDefault output directory
overwriteWhether generation can replace existing files
serverActionWhether to emit a paired Next.js server action
formProviderWhether generated output wraps the form in FormProvider
optimization.levelValidation optimization level

types

types is the explicit export list used when --export is omitted:

types: ['UserSchema', 'AdminSchema']

include / exclude

include and exclude filter exported schemas discovered from a module. They are most useful when one command should generate several forms:

npx z2f generate --config z2f.config.ts --schema src/schemas/index.ts

fields

fields applies global field-path overrides across every matching root schema:

fields: {
description: { component: 'Textarea', props: { rows: 4 } },
'rules[].expression': { component: 'ExpressionEditor' },
internalId: { hidden: true },
}

Path syntax

PatternMatches
nameTop-level field
typeCall.typeNested object field
attributes[].nameField within array items
attributes[].typeCall.typeDeep nested array/object field

Always use [] bracket notation for arrays — never items.0.field.

schemas

schemas is keyed by the exported schema constant name and has two scopes mixed into one object:

  1. Root-only generation settings
    • name
    • mode
    • out
    • serverAction
  2. Schema-identity defaults
    • component
    • fields

That second category follows the actual exported schema object anywhere it is reused as a subschema.

import * as schemaModule from './src/schemas';

export default defineConfig<typeof import('@/components/ui'), typeof schemaModule>({
components: {
source: '@/components/ui',
preset: 'shadcn',
},
schemas: {
ExpressionSchema: {
component: 'ExpressionEditor',
fields: {
language: { hidden: true },
},
},
WorkflowSchema: {
name: 'WorkflowForm',
out: 'src/forms',
fields: {
description: { component: 'Textarea', props: { rows: 6 } },
},
},
},
});

If WorkflowSchema and RuleSchema both reuse the same exported ExpressionSchema instance, both inherit ExpressionEditor unless a more specific path override wins.

Examples

1. Basic config

import { defineConfig } from '@zod-to-form/core';

export default defineConfig({
components: {
source: '@/components/ui',
preset: 'shadcn',
},
defaults: {
mode: 'submit',
out: 'src/components',
overwrite: true,
},
types: ['UserSchema'],
fields: {},
schemas: {},
});

2. Global field defaults

import { defineConfig } from '@zod-to-form/core';

export default defineConfig({
components: {
source: '@/components/ui',
preset: 'shadcn',
},
defaults: {
mode: 'auto-save',
out: 'src/components',
overwrite: true,
},
fields: {
description: { component: 'Textarea', props: { rows: 3 } },
internalId: { hidden: true },
'rules[].expression': { component: 'ExpressionEditor' },
},
});

3. Exported subschema defaults

import { defineConfig } from '@zod-to-form/core';
import * as schemaModule from './src/schemas';

export default defineConfig<typeof import('@/components/ui'), typeof schemaModule>({
components: {
source: '@/components/ui',
preset: 'shadcn',
},
defaults: {
out: 'src/components',
overwrite: true,
},
fields: {
'rules[].label': { component: 'Input' },
},
schemas: {
ExpressionSchema: {
component: 'ExpressionEditor',
fields: {
language: { hidden: true },
},
},
WorkflowSchema: {
name: 'WorkflowForm',
out: 'src/forms',
fields: {
description: { component: 'Textarea', props: { rows: 6 } },
},
},
},
});

Resolution Precedence

There are two overlapping precedence stories:

Root generation settings

For name, mode, out, and serverAction:

  1. CLI flags
  2. schemas[RootExport]
  3. defaults

Field and component behavior

For nested field rendering and schema defaults:

  1. Usage-site path overrides in schemas[RootExport].fields
  2. Global fields
  3. Schema-identity defaults from schemas[ExportedSubschema].component / .fields
  4. Metadata or processor defaults inferred by the walker

The important nuance is that schemas.ExpressionSchema.component follows the exported ExpressionSchema object anywhere it is reused, while schemas.ExpressionSchema.name does not.