Skip to main content
vertz db pull connects to an existing database, reads its tables, columns, indexes, and foreign keys, and generates a TypeScript schema file using the d builder. This is the fastest way to bring an existing database into Vertz.

Getting started

1

Configure your database connection

Add a db export to your vertz.config.ts with the connection URL and dialect:
vertz.config.ts
2

Pull the schema

Run vertz db pull to introspect the database and generate a schema file:
3

Review and customize

The generated schema is a starting point. Review it, add annotations like .readOnly(), .autoUpdate(), and .hidden(), then use it like any hand-written schema.

CLI options

Output modes

Single file (default)

Generates one schema.ts file with all tables:
src/schema.ts

Per-table mode

When the output path ends with /, each table gets its own file plus a barrel index.ts:
Each file imports its FK dependencies from sibling files:
src/schema/posts.ts

Zero-config mode

You can skip vertz.config.ts entirely by providing --url and --dialect directly:
This is useful for one-off introspection of databases you don’t have a config for.

Type mapping

The code generator maps database types to d builder calls:

Postgres

SQLite

Types that don’t map directly get d.text() with a // TODO: unmapped type comment so you can fix them manually.

What gets generated

Columns

  • Names: Snake-case column names are converted to camelCase (created_at becomes createdAt)
  • Constraints: .primary(), .unique(), .nullable() are applied based on the database schema
  • Defaults: Simple defaults (now(), true, false, numeric values, string literals) are preserved. Complex expressions (function calls, casts) are skipped.

Indexes

Indexes are generated with their original name, uniqueness, type, and WHERE clause:

Relations

Foreign keys are detected and generate d.model() with d.ref.one() relations:
  • The relation name is derived from the FK column by stripping Id or Fk suffixes (authorId becomes author)
  • Self-referential FKs work (managerId on employees references employees)
  • Multiple FKs to the same table are disambiguated (sender, usersByReceiverId)
Only d.ref.one() (many-to-one) relations are generated. Inverse d.ref.many() relations are not inferred — add them manually if needed.

Table ordering

Tables are topologically sorted so FK targets are defined before the tables that reference them. Circular references are detected, placed at the end, and annotated:

Composite primary keys

Tables with multiple primary key columns use the primaryKey option instead of .primary() on individual columns:

What is NOT generated

The code generator produces a database-level schema — the structural representation of what exists in the database. App-level annotations that carry semantic meaning are left for you to add: After pulling, review the generated schema and add these annotations where appropriate.

Preview before writing

Use --dry-run to see what would be generated without writing any files:
The generated code is printed to stdout, so you can pipe it:

Workflow: adopting Vertz on an existing database

1

Pull the schema

bash vertz db pull --output src/schema.ts
2

Review and annotate

Add .readOnly(), .autoUpdate(), .hidden(), .tenant(), and other annotations. Fix any // TODO comments for unmapped types.
3

Baseline the migration history

bash vertz db baseline This marks the current database state as the starting point — no SQL is applied.
4

Start developing

From here, use vertz dev for automatic migrations or vertz db migrate for explicit migration files. See the migrations guide for details.

Schema

Full reference for the d builder — all column types, modifiers, and annotations.

Migrations

How migrations work in development and production.