This guide will help you set up Kysely and execute your first type-safe SQL query in minutes.
1
Define Your Database Schema
Create TypeScript interfaces that describe your database structure. Kysely uses these to provide type-safety and autocompletion.
src/types.ts
import { ColumnType, Generated, Insertable, Selectable, Updateable,} from 'kysely'// Database interface - maps table names to table schemasexport interface Database { person: PersonTable pet: PetTable}// Table schema for 'person' tableexport interface PersonTable { // Generated columns (like auto-increment IDs) are marked with Generated<T> // This makes them optional in inserts and updates id: Generated<number> first_name: string // Nullable columns use TypeScript's union with null last_name: string | null gender: 'man' | 'woman' | 'other' // ColumnType allows different types for select, insert, and update created_at: ColumnType<Date, string | undefined, never>}// Helper types for working with person recordsexport type Person = Selectable<PersonTable>export type NewPerson = Insertable<PersonTable>export type PersonUpdate = Updateable<PersonTable>export interface PetTable { id: Generated<number> name: string owner_id: number species: 'dog' | 'cat'}export type Pet = Selectable<PetTable>export type NewPet = Insertable<PetTable>export type PetUpdate = Updateable<PetTable>
For production applications, consider using kysely-codegen to automatically generate types from your database schema.
2
Create a Kysely Instance
Set up a Kysely instance with your database dialect and connection details.
PostgreSQL
MySQL
SQLite
src/database.ts
import { Database } from './types'import { Kysely, PostgresDialect } from 'kysely'import { Pool } from 'pg'const dialect = new PostgresDialect({ pool: new Pool({ database: 'test', host: 'localhost', user: 'admin', port: 5432, max: 10, })})// Create a single instance and export itexport const db = new Kysely<Database>({ dialect,})
src/database.ts
import { Database } from './types'import { Kysely, MysqlDialect } from 'kysely'import { createPool } from 'mysql2'const dialect = new MysqlDialect({ pool: createPool({ database: 'test', host: 'localhost', user: 'admin', password: '123', port: 3306, connectionLimit: 10, })})export const db = new Kysely<Database>({ dialect,})
Do not import from mysql2/promise! Use the default mysql2 import.
src/database.ts
import { Database } from './types'import { Kysely, SqliteDialect } from 'kysely'import SQLite from 'better-sqlite3'const dialect = new SqliteDialect({ database: new SQLite('database.db'),})export const db = new Kysely<Database>({ dialect,})
Keep secrets safe! Never hardcode credentials. Use environment variables or a secrets manager:
Kysely provides several execution methods depending on your needs:
// executeTakeFirst() - returns first row or undefinedconst person = await db .selectFrom('person') .selectAll() .executeTakeFirst()// Type: Person | undefined// executeTakeFirstOrThrow() - throws if no rows foundconst person = await db .selectFrom('person') .selectAll() .executeTakeFirstOrThrow()// Type: Person// execute() - returns all rows as arrayconst people = await db .selectFrom('person') .selectAll() .execute()// Type: Person[]