Cerial
CLI

Generate

Read .cerial schema files and produce a fully typed TypeScript client.

The generate command reads your .cerial schema files and produces a fully typed TypeScript client.

bunx cerial generate [options]

Options

FlagAliasDescriptionDefault
--schema <path>-sPath to schema file or directory./schemas
--output <path>-oOutput directory for generated client-
--config <path>-CPath to config file-
--name <name>-nTarget a specific schema by name (multi-schema)-
--clean-cDelete entire output directory before generatingfalse
--watch-wWatch for schema changes and regeneratefalse
--verbose-vVerbose output showing generation detailsfalse
--log <level>-lLog output level: minimal, medium, or fullminimal
--formatRun the formatter on schema files during generationfalse
--help-hShow help message-

When using a config file, the -o flag is optional since output paths come from the config. Without a config, -o is required.

Examples

Generate with a config file

If you have a cerial.config.ts or cerial.config.json in your project root, just run:

bunx cerial generate

Cerial auto-discovers the config and uses its schema paths and output directories. See Configuration for setup details.

Specify a config file path

Point to a config file in a non-default location:

bunx cerial generate -C ./config/cerial.config.ts

Specify paths directly

Skip the config and pass schema and output paths on the command line:

bunx cerial generate -s ./schemas -o ./db-client

Single schema file

Generate from a single .cerial file instead of a directory:

bunx cerial generate -s ./schema.cerial -o ./generated

Target a specific schema

In a multi-schema setup, regenerate just one schema by name:

bunx cerial generate -n auth

The name matches a key in your config's schemas map. Only that schema is regenerated; the rest stay untouched. This flag requires a config file.

Watch mode

Automatically regenerate the client whenever schema files change:

bunx cerial generate --watch

Watch mode monitors your schema files and triggers regeneration each time a .cerial file is created, modified, or deleted. Changes are debounced (300ms) to coalesce rapid edits into a single rebuild.

With a multi-schema config, each schema is watched independently. A change to one schema only regenerates that schema's client.

Combine -n with --watch to focus on a single schema:

bunx cerial generate -n auth --watch

Generate with formatting

Run the .cerial formatter alongside generation:

bunx cerial generate --watch --format

Clean output

Delete the entire output directory before generating, ensuring a completely fresh output with no leftover files:

bunx cerial generate -s ./schemas -o ./db-client --clean

Without --clean, stale files from previous generations (types for renamed or removed models, for example) are automatically detected and removed after generating. The --clean flag is useful when you want a guaranteed clean slate, such as after major schema restructuring.

Verbose output

See detailed information about what the generator is doing at each step:

bunx cerial generate --verbose

What Happens During Generation

The generation process follows a nine-step pipeline.

1. Schema Discovery

The generator resolves schema files through a priority chain (see Configuration for full details):

  1. CLI flags (-s), the given path is used directly
  2. Config file, schema paths from cerial.config.ts or cerial.config.json
  3. Folder-level config, a cerial.config.ts placed inside a schema folder
  4. Convention markers, directories containing schema.cerial, main.cerial, or index.cerial
  5. Legacy fallback, a schemas/ or schema/ directory in the current working directory

Once resolved, each path can be a directory (all .cerial files are discovered and loaded) or a single file (just that one file is loaded).

2. Parsing

Each schema file is parsed into an AST. The parser recognizes:

  • model {} blocks with fields, decorators, and relations
  • object {} blocks with embedded fields
  • tuple {} blocks with typed elements
  • literal {} blocks with union variants
  • enum {} blocks with named string constants
  • Field types: String, Email, Int, Float, Bool, Date, Record, Relation, Uuid, Duration, Decimal, Bytes, Geometry, Number, Any, and type references
  • Modifiers: ? (optional), [] (array), @nullable
  • Decorators: @id, @unique, @default(), @defaultAlways(), @now, @createdAt, @updatedAt, @field(), @model(), @onDelete(), @readonly, @flexible, @set, @uuid, and more

3. Validation

The parsed schema is validated for correctness:

  • Every Relation field must reference an existing model
  • Forward relations must have a @field() decorator pointing to a valid Record field
  • Reverse relations must not have @field()
  • Record fields (except @id) must have a corresponding Relation field
  • Object, tuple, literal, and enum references must point to existing definitions
  • Decorators are checked for valid combinations and field type compatibility

4. Type Generation

TypeScript types and interfaces are generated for each model, object, tuple, literal, and enum. See Generated Output for the full list of types per kind.

// For models: full set of types
export interface User { ... }
export interface UserCreate { ... }
export interface UserUpdate { ... }
export interface UserWhere { ... }
export interface UserSelect { ... }
export interface UserInclude { ... }
export interface UserOrderBy { ... }

// For objects: subset of types
export interface Address { ... }
export interface AddressInput { ... }
export interface AddressWhere { ... }

5. Model Registry Generation

A runtime registry is generated containing metadata about every model:

  • Field names, types, optionality, and array status
  • Relation targets, directions, and field references
  • Decorator information (id, unique, default values, onDelete behavior)

The query builder uses this registry at runtime to construct correct SurrealQL queries.

6. Migration Generation

SurrealQL migration statements are generated:

DEFINE TABLE user SCHEMAFULL;
DEFINE FIELD name ON TABLE user TYPE string;
DEFINE FIELD email ON TABLE user TYPE string ASSERT string::is::email($value);
DEFINE INDEX user_email_unique ON TABLE user FIELDS email UNIQUE;

7. Client Generation

The CerialClient class is generated with:

  • connect() and disconnect() methods
  • migrate() for explicit migration
  • db proxy with typed model access

8. Formatting

All generated files are formatted with Biome and written to the output directory. Existing files in the output directory are overwritten.

9. Stale File Cleanup

After writing all files, the generator scans the output directory for .ts files that weren't part of the current generation and removes them. This handles renamed or deleted models, objects, and tuples without requiring a full directory wipe. Empty directories left behind are also cleaned up.

If --clean was used, this step is skipped since the directory was already wiped before generating.

Typical Workflow

# 1. Define your schema
# schemas/schema.cerial

# 2. Set up a config (optional, but recommended)
bunx cerial init

# 3. Generate the client
bunx cerial generate

# 4. Import and use in your app
# import { CerialClient } from './client';

# 5. During development, use watch mode
bunx cerial generate --watch

Troubleshooting

"No schema files found": Check that the schema path is correct and contains .cerial files. If you're using a config, verify the schema or schemas paths point to existing directories.

Validation errors: The generator reports which field or model has an issue. Common problems:

  • A Relation field references a model that doesn't exist
  • A Record field doesn't have a corresponding Relation (except @id fields)
  • A forward relation is missing @field()
  • Decorator conflicts (e.g., @createdAt and @default on the same field)

Output directory not created: The generator creates the output directory if it doesn't exist. If you're getting permission errors, check your file system permissions.

Stale types after renaming: The automatic cleanup should handle this. If files linger, run with --clean to wipe the output directory and regenerate fresh.

On this page