Skip to Content
🔌 Dialects & PluginsDialects

Last Updated: 3/20/2026


Dialects

A dialect is the bridge between Kysely and your database engine. It encapsulates all database-specific behavior: how to connect, how to compile queries into SQL, and how to handle database-specific features like RETURNING clauses or transactional DDL.

What Is a Dialect?

The Dialect interface (defined in src/dialect/dialect.ts) requires four factory methods:

  1. createDriver() — Returns a Driver that manages the connection pool and executes compiled queries against the database.
  2. createQueryCompiler() — Returns a QueryCompiler that transforms Kysely’s internal operation node tree into a SQL string. Different databases use different SQL syntax (e.g., PostgreSQL uses $1 placeholders, MySQL uses ?), so each dialect has its own compiler.
  3. createAdapter() — Returns a DialectAdapter that handles dialect-specific behaviors like whether the database supports RETURNING, transactional DDL, or CREATE IF NOT EXISTS.
  4. createIntrospector() — Returns a DatabaseIntrospector for reading schema metadata (table names, column names, etc.).

When you instantiate new Kysely({ dialect }), the constructor calls these factory methods to build the execution pipeline.

Built-In Dialects

Kysely ships with four built-in dialects:

PostgresDialect

Uses the pg  library. Supports RETURNING, transactional DDL, and advisory locks for migrations.

import { Kysely, PostgresDialect } from 'kysely' import { Pool } from 'pg' const db = new Kysely<Database>({ dialect: new PostgresDialect({ pool: new Pool({ host: 'localhost', database: 'my_db', user: 'postgres', password: 'secret', max: 10, }) }) })

You can also pass a function that returns a pool, which defers pool creation until the first query:

new PostgresDialect({ pool: async () => new Pool({ host: 'localhost', database: 'my_db', }) })

The PostgresAdapter (see src/dialect/postgres/postgres-adapter.ts) sets supportsTransactionalDdl and supportsReturning to true. It uses PostgreSQL’s pg_advisory_xact_lock function to acquire migration locks, which are automatically released at the end of the transaction.

MysqlDialect

Uses the mysql2  library. Does not support RETURNING (uses insertId instead) and does not support transactional DDL.

import { Kysely, MysqlDialect } from 'kysely' import { createPool } from 'mysql2' const db = new Kysely<Database>({ dialect: new MysqlDialect({ pool: createPool({ host: 'localhost', database: 'my_db', user: 'root', password: 'secret', }) }) })

Like PostgreSQL, you can pass a pool factory function. The MysqlAdapter (see src/dialect/mysql/mysql-adapter.ts) sets supportsReturning to false and supportsTransactionalDdl to false. It uses MySQL’s GET_LOCK function for migration locking.

MssqlDialect

Uses the tedious  library. Supports OUTPUT clauses (similar to RETURNING) and transactional DDL.

import { Kysely, MssqlDialect } from 'kysely' import * as Tedious from 'tedious' import * as Tarn from 'tarn' const db = new Kysely<Database>({ dialect: new MssqlDialect({ tarn: { ...Tarn, options: { min: 0, max: 10, }, }, tedious: { ...Tedious, connectionFactory: () => new Tedious.Connection({ server: 'localhost', authentication: { type: 'default', options: { userName: 'sa', password: 'secret', }, }, }), }, }) })

The MssqlAdapter (see src/dialect/mssql/mssql-adapter.ts) sets supportsOutput to true and supportsTransactionalDdl to true.

SqliteDialect

Uses the better-sqlite3  library. Supports RETURNING and transactional DDL.

import { Kysely, SqliteDialect } from 'kysely' import Database from 'better-sqlite3' const db = new Kysely<Database>({ dialect: new SqliteDialect({ database: new Database('my.db') }) })

You can also pass an async factory:

new SqliteDialect({ database: async () => new Database('my.db') })

The SqliteAdapter (see src/dialect/sqlite/sqlite-adapter.ts) sets supportsReturning and supportsTransactionalDdl to true.

DialectAdapter

The DialectAdapter interface (defined in src/dialect/dialect-adapter.ts) exposes several boolean flags that control Kysely’s behavior:

  • supportsReturning — Whether the database supports RETURNING clauses in INSERT, UPDATE, and DELETE statements. PostgreSQL and SQLite support this; MySQL does not.
  • supportsOutput — Whether the database supports OUTPUT clauses (SQL Server).
  • supportsTransactionalDdl — Whether the database supports running DDL statements (like CREATE TABLE) inside a transaction. PostgreSQL, SQLite, and SQL Server support this; MySQL does not. When true, Kysely runs migrations inside a transaction.
  • supportsCreateIfNotExists — Whether the database supports IF NOT EXISTS in CREATE TABLE and similar statements.

The adapter also defines acquireMigrationLock and releaseMigrationLock methods, which Kysely calls to ensure only one migration runs at a time. Each dialect implements this differently: PostgreSQL uses advisory locks, MySQL uses GET_LOCK, and SQLite uses a row lock on the migration lock table.

Community Dialects

The Kysely ecosystem includes community-maintained dialects for databases not covered by the built-in set:

Each dialect wraps a different database driver and implements the Dialect interface. You use them the same way as the built-in dialects: pass an instance to the dialect option when creating a Kysely instance.

When to Write a Custom Dialect

You need a custom dialect when:

  1. You want to use a database engine not covered by the built-in or community dialects.
  2. You need to customize query compilation (e.g., to support a non-standard SQL variant).
  3. You need to integrate a custom connection pool or driver.

To write a custom dialect, implement the Dialect interface and provide implementations for createDriver, createQueryCompiler, createAdapter, and createIntrospector. Study the built-in dialects in src/dialect/*/ for reference.

What’s Next

  • Plugins — Learn how to transform queries and results with the plugin system.
  • Schema Builder — Use db.schema to create and alter tables, indexes, and views.
  • Generating Types — Automatically generate your Database interface from your schema.