1
0
mirror of https://github.com/theoludwig/kysely-typegen.git synced 2026-05-22 16:23:25 +02:00
Files
kysely-typegen/README.md
T
theoludwig e9adb364e0 refactor!: move KyselyTypegenPostgresDialect export to /postgres
To prepare for additional dialects and keep the default entry tiny,
`KyselyTypegenPostgresDialect` is now exported from a dedicated
`kysely-typegen/postgres` subpath instead of the package root.

The `KyselyTypegenDialect` base class is also reworked to support
dialects where enums are declared per-column rather
than as a named top-level type. The abstract `getEnumsMap()` method
is replaced by an optional `introspectEnums()` hook returning both
`named` and `inline` enums.

BREAKING CHANGE: `KyselyTypegenPostgresDialect` is no longer exported
from `kysely-typegen`. Import it from `kysely-typegen/postgres`.

Before:

```ts
import { KyselyTypegenPostgresDialect } from "kysely-typegen"
```

After:

```ts
import { KyselyTypegenPostgresDialect } from "kysely-typegen/postgres"
```

BREAKING CHANGE: custom dialects extending `KyselyTypegenDialect`
must replace `protected getEnumsMap()` with `protected introspectEnums()`,
which returns `{ named, inline }` instead of a flat `Map<string, string[]>`.

Before:

```ts
protected async getEnumsMap(): Promise<Map<string, string[]>> {
  return new Map([["Role", ["admin", "member"]]])
}
```

After:

```ts
protected override async introspectEnums(): Promise<IntrospectedEnums> {
  return {
    named: [{ name: "Role", values: ["admin", "member"] }],
    inline: new Map(),
  }
}
```
2026-05-22 15:59:38 +02:00

6.9 KiB

kysely-typegen

version license

Generate Kysely type definitions from your database.

Thank you kysely-codegen for inspiration and ideas!

Why?

Why kysely-typegen if there is already kysely-codegen? Comparison:

kysely-codegen@0.20.0 kysely-typegen
Install Size 6.8 MB 5 kB
Dependencies 35 total 0 (no runtime dependencies)
Type CLI Library/Programmatic Usage
Code Size/Maintainability Heavy Lightweight/Simple and straightforward (string manipulation instead of complex AST)
Database Support PostgreSQL, MySQL, SQLite, MSSQL, LibSQL PostgreSQL (can be easily extended to more)

kysely-typegen is a library (not a CLI), which means you are in control of where and how to run it, and is designed to be extensible, easy to add support for more database dialects.

For example: you can use Node.js with the --env-file CLI option, dotenv dependency is not required (but can be used), you are in control.

Note: kysely-typegen doesn't have the same features and customization as kysely-codegen, it has less features to keep it simple and lightweight, but can be extended to your own needs. For more details, why this project was created, and the design decisions, see: https://github.com/RobinBlomberg/kysely-codegen/issues/175.

Prerequisites

Node.js >= 24.0.0

Installation

npm install --save-dev kysely-typegen

Peer dependencies:

npm install kysely

Plus a Kysely dialect driver for your database (see Setup Kysely database below).

Usage

Setup Kysely database

Create your Kysely database instance and export a databaseTypegen for the script in the next section. The rest of the guide is dialect-agnostic: only this file changes per database.

PostgreSQL

KyselyTypegenPostgresDialect works with any Kysely PostgreSQL dialect, including the built-in PostgresDialect (using pg) and PostgresJSDialect (using postgres). The example below uses kysely-postgres-js.

npm install kysely-postgres-js postgres
// database.ts
import { Kysely } from "kysely"
import { PostgresJSDialect } from "kysely-postgres-js"
import { KyselyTypegenPostgresDialect } from "kysely-typegen/postgres"
import postgres from "postgres"

import type { DB } from "./codegen.ts"

const dialect = new PostgresJSDialect({
  postgres: postgres({
    database: process.env["DATABASE_NAME"] ?? "database",
    host: process.env["DATABASE_HOST"] ?? "localhost",
    user: process.env["DATABASE_USER"] ?? "user",
    password: process.env["DATABASE_PASSWORD"] ?? "password",
    port: Number.parseInt(process.env["DATABASE_PORT"] ?? "5432", 10),
  }),
})

export const database = new Kysely<DB>({ dialect })
export const databaseTypegen = new KyselyTypegenPostgresDialect({ database })

Generate the type definitions

Create a script that uses databaseTypegen to introspect your database and write the generated types to a file. This script is the same regardless of the underlying database:

// scripts/typegen.ts
// This is an example, you can be more creative:
// time it takes to generate, number of tables/enums generated, etc.
import fs from "node:fs"
import path from "node:path"

import { database, databaseTypegen } from "./database.ts"

const result = await databaseTypegen.typegen()
const codegenContent = result.lines.join("\n")
const codegenPath = path.join(process.cwd(), "codegen.ts")
await fs.promises.writeFile(codegenPath, codegenContent, "utf-8")
await database.destroy()

Run with Node.js (using --env-file to load environment variables, no dotenv dependency required):

node --env-file=.env scripts/typegen.ts

Using the type definitions

Import DB into new Kysely<DB>, and you're done!

import { database } from "./database.ts"

const rows = await database.selectFrom("User").selectAll().execute()
//    ^ { createdAt: Date; email: string; id: number; ... }[]

Fully type-safe queries derived from your actual database schema.

Extending to other database dialects

kysely-typegen ships with KyselyTypegenPostgresDialect, but you can add support for any database by extending the abstract KyselyTypegenDialect class.

Only one thing is required:

  • scalars: a Record<string, string> mapping the database column types to TypeScript types.
import { KyselyTypegenDialect } from "kysely-typegen"

export class KyselyTypegenMSSQLDialect extends KyselyTypegenDialect {
  public override readonly scalars: Record<string, string> = {
    bigint: "Int8",
    bit: "boolean",
    char: "string",
    datetime: "Timestamp",
    decimal: "Numeric",
    int: "number",
    nvarchar: "string",
    smallint: "number",
    text: "string",
    varbinary: "Buffer",
    varchar: "string",
    // ...
  }
}

If your database supports enums, override the optional introspectEnums() hook, which returns two maps:

  • named: enum name → values (emitted as export type Name = "a" | "b").
  • inline: ${tableName}.${columnName} → values (emitted inline at the column site, for databases where enums are anonymous per-column).
import type { IntrospectedEnums } from "kysely-typegen"

protected override async introspectEnums(): Promise<IntrospectedEnums> {
  // Query your database's information schema...
  return { named: [], inline: new Map() }
}

The base class handles introspection (via Kysely's database.introspection.getTables()), sorting, and the final type generation. Contributions of new dialects are welcome!

Contributing

Anyone can help to improve the project, submit a Feature Request, a bug report or even correct a simple spelling mistake.

The steps to contribute can be found in the CONTRIBUTING.md file.

License

MIT