Telaio
CLI

Generate Database Types

Generate TypeScript types from your live database schema using telaio db:types.

Generate Database Types

pnpx telaio db:types

telaio db:types generates TypeScript interfaces from your live PostgreSQL schema using kysely-codegen. The output is used as the DB generic for createDatabase<DB>(), which makes all Kysely queries fully typed against your actual schema.

Peer dependency

pnpm add -D kysely-codegen

Default behavior

telaio db:types runs kysely-codegen with the following flags applied by default:

FlagDescription
--camel-caseConverts snake_case column names to camelCase in the generated types, matching the Kysely CamelCasePlugin that Telaio enables by default
--runtime-enumsGenerates runtime enum objects in addition to TypeScript types
--singularizeConverts plural table names to singular type names (e.g. users table becomes User type)

Output

Generated types are written to src/db/types.ts:

// src/db/types.ts (generated — do not edit)
export interface User {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
}

export interface Post {
  id: string;
  userId: string;
  title: string;
  body: string;
  publishedAt: Date | null;
  createdAt: Date;
}

export interface DB {
  users: User;
  posts: Post;
}

Using the generated types

Pass the DB interface as the generic to createDatabase:

import type { DB } from './db/types.js';
import { createPool, createDatabase } from 'telaio/db';

const pool = await createPool(config);
const db = await createDatabase<DB>(pool);

// All queries are now typed against your actual schema:
const user = await db
  .selectFrom('users')
  .where('id', '=', userId)
  .selectAll()
  .executeTakeFirstOrThrow();

// user.email is typed as string
// user.createdAt is typed as Date

When using the builder, cast app.db to the typed version:

import type { DB } from './db/types.js';
import type { Kysely } from 'kysely';

const app = await createApp({ config }).withDatabase().build();

const db = app.db as Kysely<DB>;

Connection

telaio db:types reads DATABASE_URL from the environment (or your .env file) to connect to the database and introspect the schema. The database must be running and accessible when you run the command.

DATABASE_URL=postgres://user:pass@localhost:5432/mydb pnpx telaio db:types

Or set it in .env:

DATABASE_URL=postgres://user:pass@localhost:5432/mydb

Re-run telaio db:types after every migration that changes the schema. Keeping the generated types in sync with the database schema ensures that TypeScript catches column renames, type changes, and dropped columns at compile time.

The generated src/db/types.ts file is overwritten on every run. Do not add manual changes to this file -- put custom type augmentations in a separate file and import from there.

On this page