NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #3677 most downloaded on npm
Type safe SQL query builder
Last release 19 days ago
16 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 55 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
189 releases · first in 2021
One column per quarter.
Fixes a potential security issue #121. Thank you @DavesBorges ❤️
Fixes a potential security issue #121. Thank you @DavesBorges ❤️
Adds query streaming. Thank you @elderapo ❤️
Added createType and dropType methods to the schema builder.
Added createType and dropType methods to the schema builder.
Added modifyFront and modifyEnd methods
Added modifyFront and modifyEnd methods
Fix bug where falsy default values didn't set the hasDefaultValue value to true in ColumnMetadata.
Fix bug where falsy default values didn't set the hasDefaultValue value to true in ColumnMetadata.
Nothing published for this version
Added isAutoIncrementing and hasDefaultValue to ColumnMetadata.
Added isAutoIncrementing and hasDefaultValue to ColumnMetadata.
``ts const query = ctx.db .selectFrom('person') .innerJoinLateral( (eb) => eb.selectFrom('pet') .select('name') .whereRef('pet.owner_id', '=', 'person
Add support for lateral joins
const query = ctx.db
.selectFrom('person')
.innerJoinLateral(
(eb) =>
eb.selectFrom('pet')
.select('name')
.whereRef('pet.owner_id', '=', 'person.id')
.as('p'),
(join) => join.on(sql`true`)
)
.select(['first_name', 'p.name'])
.orderBy('first_name')
Fix join method issues that caused typescript to fail with Type instantiation is excessively deep and possibly infinite.ts(2589)-
Fix join method issues that caused typescript to fail with Type instantiation is excessively deep and possibly infinite.ts(2589)-
Enables tree shaking for webpack
FileMigrationProvider.mjs files in migrationsNothing published for this version
The addColumn method of AlterTableBuilder now takes a third callback argument just like CreateTableBuilder.addColumn.
The addColumn method of AlterTableBuilder now takes a third callback argument just like CreateTableBuilder.addColumn.
Kysely now has absolutely no internal dependecies to anything. Not even dynamic ones. The same code runs on node, deno, browser and is compatible with
Kysely now has absolutely no internal dependecies to anything. Not even dynamic ones. The same code runs on node, deno, browser and is compatible with all bundlers out of the box! All dependencies are passed from the outside.
The dialects now take an instance of the underlying db drivers's pool (or other connection object if a pool is not available). This is how you'd create an instance of Kysely in 0.19.0:
import { Pool } from 'pg'
const db = new Kysely<Database>({
dialect: new PostgresDialect({
pool: new Pool({
host: 'localhost',
database: 'kysely_test'
})
})
})
import { createPool } from 'mysql2'
const db = new Kysely<Database>({
dialect: new MysqlDialect({
pool: createPool({
host: 'localhost',
database: 'kysely_test'
})
})
})
import Database from 'better-sqlite3'
const db = new Kysely<Database>({
dialect: new SqliteDialect({
database: new Database('db.sqlite')
})
})
If you want to initialize the pool lazily when it's used for the first time, you can use a thunk:
import { Pool } from 'pg'
const db = new Kysely<Database>({
dialect: new PostgresDialect({
pool: async () => new Pool({
host: 'localhost',
database: 'kysely_test'
})
})
})
I also changed the FileMigrationProvider once again, even though I promised never to do that again 😞. This was done to get rid of all dependencies. You now need to use the class like this:
import { promises as fs } from 'fs'
import path from 'path'
new FileMigrationProvider({
fs,
path,
migrationFolder: 'path/to/migrations/folder',
})
There's no more need for the index-nodeless file and it has been removed. You can simply import kysely or the index.ts file from the dist folder. Nothing refers to node or any node library.
Allow custom migration tables and schema #80
MysqlDialect and PostgresDialect #81UpdateQueryBuilder now takes four type arguments instead of three. The second argument is new and is the table that will be updated. The third one is
UpdateQueryBuilder now takes four type arguments instead of three. The second argument is new and is the table that will be updated. The third one is a union of all the tables that can be referred to.
This only affects you if you've been using explicit types.
UpdateQueryBuilderas method of a raw sql snippet.Actually fix https://github.com/koskimas/kysely/issues/73
Fix https://github.com/koskimas/kysely/issues/73
support starting transactions from single connections
db.raw has been replaced with the sql template tag. sql is a free function that can be used with or without a Kysely instance.
db.raw has been replaced with the sql template tag. sql is a free function that can be used with or without a Kysely instance.
See the docs for detailed instructions. Here's how you'd replace the most common use cases of the old db.raw:
import { sql } from 'kysely'
// old
db.raw('select first_name from person where id = ?', [id])
// new
sql`select first_name from person where id = ${id}`
import { sql } from 'kysely'
// old
db.raw('select ?? from person', ['first_name'])
// new
sql`select ${sql.ref('first_name')} from person`
import { sql } from 'kysely'
// old
const result = await db.raw('select first_name from person where id = ?', [id]).execute()
// new
const result = await sql`select first_name from person where id = ${id}`.execute(db)
Added orderBy and limit methods for DeleteQueryBuilder
orderBy and limit methods for DeleteQueryBuilderNothing published for this version
Added the getMigrations method for Migrator.
Migrator.Add a RawBuilder constructor that can be easily used without a Kysely instance.
RawBuilder constructor that can be easily used without a Kysely instance.Added the if method. Also see this recipe.
Fix bug where RuntimeDriver was accidentally passed to dialect driver methods.
Fix bug where RuntimeDriver was accidentally passed to dialect driver methods.
Remove mostly useless PrimitiveValue type. This should improve compatibility with deno and browsers.
Remove mostly useless PrimitiveValue type. This should improve compatibility with deno and browsers.
Use string literals in dynamic imports to make esbuild happy.
Use string literals in dynamic imports to make esbuild happy.
Add ref method to ExpressionBuilder.
Add ref method to ExpressionBuilder.
Make Buffer optional. Required to make certain features work in browsers and deno.
Make Buffer optional. Required to make certain features work in browsers and deno.
Add couple of missing .js extensions to imports.
Add couple of missing .js extensions to imports.
Sorry for making this many breaking changes so fast. The API is finding its shape and things will calm down soon. I promise 😊
The first two arguments of FileMigrationProvider have been removed.
Sorry for making this many breaking changes so fast. The API is finding its shape and things will calm down soon. I promise 😊
Add a forgotten exports to package.json file for the index-nodeless file.
Add a forgotten exports to package.json file for the index-nodeless file.
Added an exprimental index-nodeless entry point that doesn't export any node.js dependencies.
Added an exprimental index-nodeless entry point that doesn't export any node.js dependencies.
import {
CompiledQuery,
DatabaseConnection,
DatabaseIntrospector,
DatabaseMetadata,
DatabaseMetadataOptions,
DefaultQueryCompiler,
Dialect,
DialectAdapter,
Driver,
Kysely,
MIGRATION_LOCK_TABLE,
MIGRATION_TABLE,
QueryCompiler,
} from 'kysely/dist/cjs/index-nodeless.js'; // <-- The .js at the end is required
Optionally you can import the ESM version from kysely/dist/esm/index-nodeless.js
Fix a bug in returningAll return type when using ColumnType.
Fix a bug in returningAll return type when using ColumnType.
New ColumnType and Generated interfaces for defining separate interfaces for select, insert and update operations. See the example in the readme for m
select, insert and update operations. See the example in the readme for more info.db.migrate module has been removed. You now need to create an instance of Migrator instead.Generated interface removes the need for db.generated which has now been removed. Simply mark your db-generated columns with Generated<T> in the table interface and remove db.generated.Before:
interface Person {
id: number,
first_name: string
}
await db.insertInto('person').values({
id: db.generated,
first_name: 'Jennifer'
})
Now:
interface PersonTable {
id: Generated<number>,
first_name: string
}
type Person = Selectable<PersonTable>
await db.insertInto('person').values({
first_name: 'Jennifer'
})
Removed a magical UnionToIntersection type that made it difficult to write generic helpers.
Removed a magical UnionToIntersection type that made it difficult to write generic helpers.
Kysely now supports all the features of SQLite on conflict clause (almost all features of the PostgreSQL on conflict clause)
expression methods in the schema module previously took a raw SQL string. Those all now take a db.raw instance instead for consistency.// Before
db.schema
.alterTable('person')
.addCheckConstraint('some_constraint', 'a < b')
// Now
db.schema
.alterTable('person')
.addCheckConstraint('some_constraint', db.raw('a < b'))
onConflictDoNothing and onConflictUpdate methods have been replaced by a single onConflict method.// Before
db.insertInto('pet').values(pet).onConflictUpdate('name', updates)
// Now
db.insertInto('pet').values(pet).onConflict(
// Also see the `columns` and `constraint` methods.
(oc) => oc.column('name').doUpdateSet(updates)
)
// Before
db.insertInto('pet').values(pet).onConflictDoNothing('name')
// Now
db.insertInto('pet').values(pet).onConflict(
(oc) => oc.column('name').doNothing()
)
Added migrateTo, migrateUp and migrateDown methods.
Added withRecursive for recursive common table expressions.
Make jsdoc comments better accessible by copying them from the interfaces to the implementing classes. This is done automatically as a build step.
Make jsdoc comments better accessible by copying them from the interfaces to the implementing classes. This is done automatically as a build step.
Created separate query builders for select, insert, update and delete queries. This is only a breaking change if you have used the QueryBuilder type e…
subQuery method to selectFrom.QueryBuilder type explicitly.Support callback subqueries and raw expressions in insert queries:
Support callback subqueries and raw expressions in insert queries:
db.with('jennifer', (db) => db
.selectFrom('person')
.where('first_name', '=', 'Jennifer')
.select(['id', 'first_name'])
.limit(1)
).insertInto('pet').values({
id: db.generated,
owner_id: (eb) => eb.subQuery('jennifer').select('id'),
name: (eb) => eb.subQuery('jennifer').select('first_name'),
species: 'cat',
})
`ts const db = new Kysely ({ dialect: new PostgresDialect(postgresConfig), log(event) { if (event.level === 'query') { console.log(event.query.sql) co
Support custom log function:
const db = new Kysely<Database>({
dialect: new PostgresDialect(postgresConfig),
log(event) {
if (event.level === 'query') {
console.log(event.query.sql)
console.log(event.query.parameters)
}
}
})
Accept a single raw argument in where, having and on statements. For example
Accept a single raw argument in where, having and on statements. For example
where(db.raw('foo between ? and ?', [a, b]))
Implement SQLite introspector.
Implement SQLite introspector.
Added support for SQLite using the better-sqlite3 library.
Added support for SQLite using the better-sqlite3 library.
number | undefinednumbernumberbigint to support large integers. Also the QueryResult. insertedPrimaryKey field has been renamed to insertId. QueryResult is only returned by completely raw queries like await db.raw('select * from person').Use performance.now instead of process.hrtime to time query execution.
Use performance.now instead of process.hrtime to time query execution.
Add support for materialized views
increments method in the schema module is now called autoIncrement. You need to go through your migrations and use the new method.isPrimaryKey are now renamed to primaryKey. This only affects you if you've implemented your own plugins that transform the operation node tree.Added createView and dropView methods to the schema module.
Added createView and dropView methods to the schema module.
Added operators ||, @@, @@@, !! and <->
Added operators ||, @@, @@@, !! and <->
Added node 16 requirement to package.json.
Added node 16 requirement to package.json.
Nothing published for this version
- Added the error log level. - Added the withPlugin method.
Added initial minimal query logging.
Added the union and unionAll methods.
Changed the type of CompiledQuery.parameters from any[] to unknown[].
Changed the type of CompiledQuery.parameters from any[] to unknown[].
- Fixed the noWait method - General code cleanup
ColumnDefinitionBuilder.increments() no longer converts the column's data type to serial or bigserial on postgres, but instead always adds an auto_inc
increments() no longer works on PostgreSQL.ColumnDefinitionBuilder.increments() no longer converts the column's data type to serial or bigserial on postgres, but instead always adds an auto_increments specifier. This means that you need to remove increments calls in postgres migrations and use the serial or bigserial data type directly. Simply remove the increments call and change int or integer to serial and bigint or biginteger to bigserial on that column.
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →