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.
'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true .
Hey 👋
0.30 season is upon us. pnpm i kysely@next and get a sneak peak into the future!
We've got a new transactionMode: 'per-run' | 'per-migration' | 'none' property you can pass to Migrator or it's methods.
'per-run' is the classic behavior you're used to where kysely wrap the entire run in a transaction when your dialect supports transactional DDL.'per-migration' enables each migration to pick whether it runs in its own transaction or not. Just expose config: { transaction: false } from the module, right next to the up/down functions.'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true.import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import { FileMigrationProvider, Migrator } from 'kysely/migration'
const migrator = new Migrator({
db,
provider: new FileMigrationProvider({
fs,
migrationFolder: path.join(import.meta.dirname, 'migrations'),
}),
transactionMode: 'per-migration', // <-------------------------------
})
await migrator.migrateToLatest()We've got a new defineMigration helper function that you can use to easily write your migrations and meet the contract requirements:
import { defineMigration } from 'kysely/migration'
export default defineMigration({
up: async (db) => {
// ...
},
config: { transaction: false }, // <--------------------
})You can now use mysql2/promise, where in the past it would hang forever since we only supported the callback style of mysql2 root import.
We're trying various type-level solutions that provide compilation performance and type-safety improvements of Kysely, Transaction, ControlledTransaction and their readonly variants. QueryCreator, FunctionModule, MergeQueryBuilder too.
We've got a new stream method on RawBuilder that allows you to:
import { sql } from 'kysely'
import { db } from 'path/to/db'
for await (const row of sql`select * from person`.stream(db)) {
// ...
}migrateTo(name, { direction: 'Up' | 'Down' }) to enforce direction. by @igalklebanov in #1957where option for partial introspection. by @igalklebanov in #2005where option in getSchemas. by @igalklebanov in #2006comment property in table metadata. by @igalklebanov in #2008mysql2 and mysql2/promise in MysqlDialect. by @igalklebanov in #1958withNonDefaultDatabases to support introspection of non-default databases. by @igalklebanov in #2007ControlledTransaction<any> to satisfy Transaction<DB>. by @igalklebanov in #2027DummyDriver execution JSDoc. by @igalklebanov in #2032disableTransactions is deprecated. Use the new transactionMode: 'none', or transactionMode: 'per-migration' with combination of config: { transaction: false }.mysql, information_schema, performance_schema, sys and nbinfo tables will not be returned.Kysely, Transaction, ControlledTransaction and their readonly variants are compared more tightly. QueryCreator, FunctionModule, MergeQueryBuilder too. Please report these cases.BLOB columns in JSON helpers emits compile-time errors - e.g.
KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>Full Changelog: v0.29.5...v0.30.0-beta.2
'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true.
Hey 👋
0.30 season is upon us. pnpm i kysely@next and get a sneak peak into the future!
We've got a new transactionMode: 'per-run' | 'per-migration' | 'none' property you can pass to Migrator or it's methods.
'per-run' is the classic behavior you're used to where kysely wrap the entire run in a transaction when your dialect supports transactional DDL.'per-migration' enables each migration to pick whether it runs in its own transaction or not. Just expose config: { transaction: false } from the module, right next to the up/down functions.'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true.import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import { FileMigrationProvider, Migrator } from 'kysely/migration'
const migrator = new Migrator({
db,
provider: new FileMigrationProvider({
fs,
migrationFolder: path.join(import.meta.dirname, 'migrations'),
}),
transactionMode: 'per-migration', // <-------------------------------
})
await migrator.migrateToLatest()
We've got a new defineMigration helper function that you can use to easily write your migrations and meet the contract requirements:
import { defineMigration } from 'kysely/migration'
export default defineMigration({
up: async (db) => {
// ...
},
config: { transaction: false }, // <--------------------
})
You can now use mysql2/promise, where in the past it would hang forever since we only supported the callback style of mysql2 root import.
migrateTo(name, { direction: 'Up' | 'Down' }) to enforce direction. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1957mysql2 and mysql2/promise in MysqlDialect. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1958disableTransactions is deprecated. Use the new transactionMode: 'none', or transactionMode: 'per-migration' with combination of config: { transaction: false }.BLOB columns in JSON helpers emits compile-time errors - e.g.KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>
Full Changelog: https://github.com/kysely-org/kysely/compare/4ba0bd495a4cbe11d8d58ef02537586dc4d56532...v0.30.0-beta.1
Hey 👋
0.30 season is upon us. pnpm i kysely@next and get a sneak peak into the future!
We've got a new transactionMode: 'per-run' | 'per-migration' | 'none' property you can pass to Migrator or it's methods.
'per-run' is the classic behavior you're used to where kysely wrap the entire run in a transaction when your dialect supports transactional DDL.'per-migration' enables each migration to pick whether it runs in its own transaction or not. Just expose config: { transaction: false } from the module, right next to the up/down functions.'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true.import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import { FileMigrationProvider, Migrator } from 'kysely/migration'
const migrator = new Migrator({
db,
provider: new FileMigrationProvider({
fs,
migrationFolder: path.join(import.meta.dirname, 'migrations'),
}),
transactionMode: 'per-migration', // <-------------------------------
})
await migrator.migrateToLatest()We've got a new defineMigration helper function that you can use to easily write your migrations and meet the contract requirements:
import { defineMigration } from 'kysely/migration'
export default defineMigration({
up: async (db) => {
// ...
},
config: { transaction: false }, // <--------------------
})You can now use mysql2/promise, where in the past it would hang forever since we only supported the callback style of mysql2 root import.
migrateTo(name, { direction: 'Up' | 'Down' }) to enforce direction. by @igalklebanov in #1957mysql2 and mysql2/promise in MysqlDialect. by @igalklebanov in #1958disableTransactions is deprecated. Use the new transactionMode: 'none', or transactionMode: 'per-migration' with combination of config: { transaction: false }.BLOB columns in JSON helpers emits compile-time errors - e.g.
KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>Full Changelog: 4ba0bd4...v0.30.0-beta.1
'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true.
Hey 👋
0.30 season is upon us. pnpm i kysely@next and get a sneak peak into the future!
We've got a new transactionMode: 'per-run' | 'per-migration' | 'none' property you can pass to Migrator or it's methods.
'per-run' is the classic behavior you're used to where kysely wrap the entire run in a transaction when your dialect supports transactional DDL.'per-migration' enables each migration to pick whether it runs in its own transaction or not. Just expose config: { transaction: false } from the module, right next to the up/down functions.'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true.import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import { FileMigrationProvider, Migrator } from 'kysely/migration'
const migrator = new Migrator({
db,
provider: new FileMigrationProvider({
fs,
migrationFolder: path.join(import.meta.dirname, 'migrations'),
}),
transactionMode: 'per-migration', // <-------------------------------
})
await migrator.migrateToLatest()
We've got a new defineMigration helper function that you can use to easily write your migrations and meet the contract requirements:
import { defineMigration } from 'kysely/migration'
export default defineMigration({
up: async (db) => {
// ...
},
config: { transaction: false }, // <--------------------
})
disableTransactions is deprecated. Use the new transactionMode: 'none', or transactionMode: 'per-migration' with combination of config: { transaction: false }.BLOB columns in JSON helpers emits compile-time errors - e.g.KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>
Full Changelog: https://github.com/kysely-org/kysely/compare/4ba0bd495a4cbe11d8d58ef02537586dc4d56532...v0.30.0-beta.0
Hey 👋
0.30 season is upon us. pnpm i kysely@next and get a sneak peak into the future!
We've got a new transactionMode: 'per-run' | 'per-migration' | 'none' property you can pass to Migrator or it's methods.
'per-run' is the classic behavior you're used to where kysely wrap the entire run in a transaction when your dialect supports transactional DDL.'per-migration' enables each migration to pick whether it runs in its own transaction or not. Just expose config: { transaction: false } from the module, right next to the up/down functions.'none' means no transactions are used, which is similar to the now deprecated disableTransactions: true.import * as fs from 'node:fs/promises'
import * as path from 'node:path'
import { FileMigrationProvider, Migrator } from 'kysely/migration'
const migrator = new Migrator({
db,
provider: new FileMigrationProvider({
fs,
migrationFolder: path.join(import.meta.dirname, 'migrations'),
}),
transactionMode: 'per-migration', // <-------------------------------
})
await migrator.migrateToLatest()We've got a new defineMigration helper function that you can use to easily write your migrations and meet the contract requirements:
import { defineMigration } from 'kysely/migration'
export default defineMigration({
up: async (db) => {
// ...
},
config: { transaction: false }, // <--------------------
})disableTransactions is deprecated. Use the new transactionMode: 'none', or transactionMode: 'per-migration' with combination of config: { transaction: false }.BLOB columns in JSON helpers emits compile-time errors - e.g.
KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>Full Changelog: 4ba0bd4...v0.30.0-beta.0
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
doUpdateSet's where. by @igalklebanov in #2043Full Changelog: v0.29.5...v0.29.6
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
TypeScript 7 is allowing for deeper computations which now cause way more instantiations and wall clock times in various scenarios. We're diving deep into our types and finding optimizations. In this version @koskimas brought some nice wins for builder vs. builder assignability checks.
We're also revamping the docs site, working on style, message and usefulness. Swing by our Discord and share your opinions/ideas. We got docs->apidocs search now. The playground is back supporting short links and will allow saving short links very soon.
CreateTypeBuilder.asEnum docstring by @anonpay-sh in #1949Full Changelog: v0.29.4...v0.29.5
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.29.3...v0.29.4
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Full Changelog: v0.29.3...v0.29.4
chore: resolve audit vulnerabilities. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1882
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
disableTransactions: true. by @morgan-coded & @igalklebanov in https://github.com/kysely-org/kysely/pull/1919zizmor persona. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1869Full Changelog: https://github.com/kysely-org/kysely/compare/v0.29.2...v0.29.3
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
disableTransactions: true. by @morgan-coded & @igalklebanov in #1919zizmor persona. by @igalklebanov in #1869Full Changelog: v0.29.2...v0.29.3
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
$narrowType mishandling branded types. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1851Full Changelog: https://github.com/kysely-org/kysely/compare/v0.29.1...v0.29.2
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
$narrowType mishandling branded types. by @igalklebanov in #1851Full Changelog: v0.29.1...v0.29.2
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
zizmor scans. by @igalklebanov in #1843Full Changelog: v0.29.0...v0.29.1
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
zizmor scans. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1843Full Changelog: https://github.com/kysely-org/kysely/compare/v0.29.0...v0.29.1
db.deleteFrom('person') // compilation error + deprecation! db.insertInto('person').values({...}) // compilation error + deprecation! db.mergeInto('pe…
Hey 👋
This one's a banger! 💥 💥 💥
We got $pickTables, $omitTables compile-time helpers to narrow the world view of downstream queries, cutting down on compilation complexity/time while at it!
const results = await db
.$pickTables<'person' | 'pet'>() // <----- now `DB` is only { person: {...}, pet: {...} } for following methods.
.selectFrom('person')
.innerJoin('pet', 'pet.owner_id', 'person.id')
.selectAll()
.execute()
const results = await db
.$omitTables<'toy'>() // <----- now `DB` doesn't have a "toy" table description for following methods.
.selectFrom('person')
.innerJoin('pet', 'pet.owner_id', 'person.id')
.selectAll()
.execute()
We got a new ReadonlyKysely<DB> helper type that turns your instance into a compile-time readonly instance!
import { Kysely } from 'kysely'
import type { ReadonlyKysely } from 'kysely/readonly'
export const db = new Kysely<Database>({...}) as never as ReadonlyKysely<Database>
db.selectFrom('person').selectAll() // no problem.
db.selectNoFrom(sql`now()`.as('now')) // no problem.
db.deleteFrom('person') // compilation error + deprecation!
db.insertInto('person').values({...}) // compilation error + deprecation!
db.mergeInto('person')... // compilation error + deprecation!
db.updateTable('person').set('first_name', 'Timmy') // compilation error + deprecation!
sql`...`.execute(db) // compilation error!
// etc. etc.
We got a brand new PGlite dialect. With it comes a new supportsMultipleConnections adapter flag that uses a new centralized connection mutex when false - should help simplify all SQLite dialects out here!
import { PGlite } from '@electric-sql/pglite'
import { Kysely, PGliteDialect } from 'kysely'
const db = new Kysely<DB>({
// ...
dialect: new PGliteDialect({
pglite: new PGlite(),
}),
// ...
})
We got $narrowType supporting nested narrowing and discriminated unions!
db.selectFrom('person_metadata')
.select(['discriminatedUnionProfile'])
// output type inferred as:
//
// {
// discriminatedUnionProfile: {
// auth:
// | { type: 'token'; token: string }
// | { type: 'session'; session_id: string }
// tags: string[]
// }
// }[]
.$narrowType<{ discriminatedUnionProfile: { auth: { type: 'token' } } }>()
// output type narrowed to:
//
// {
// discriminatedUnionProfile: {
// auth: { type: 'token'; token: string }
// tags: string[]
// }
// }[]
.execute()
We got web standards driven query cancellation support. Pass an abort signal to execute* methods and similar. Pick between different inflight query abort strategies - ignore the query, cancel it on the database side or even kill the session on the database side.
import { Kysely, PostgresDialect } from 'kysely'
import { Client, ... } from 'pg'
const db = new Kysely<Database>({
dialect: new PostgresDialect({
// ...
controlClient: Client, // optional, for out-of-pool connections for database side query aborts.
// ...
})
})
const options = { signal: AbortSignal.timeout(3_000) } // throw abort/timeout errors and ignore query reuslts
query.execute(options)
query.stream(options)
sql`...`.execute(db, options)
db.executeQuery(compiledQuery, options)
// etc. etc.
query.execute({ ...options, inflightQueryAbortStrategy: 'cancel query' }) // also cancel query database side
query.execute({ ...options, inflightQueryAbortStrategy: 'kill session' }) // also kill session database side
We got SafeNullComparisonPlugin to flip (in)equality operators to is and is not when right hand side argument is null.
import { Kysely, SafeNullComparisonPlugin } from 'kysely'
const db = new Kysely<DB>({
// ...
plugins: [new SafeNullComparisonPlugin()],
// ...
})
db.selectFrom('pet')
.where('name', '=', null) // outputs: "name" is null
.where('owner_id', '!=', null) // outputs: "owner_id" is not null
.selectAll()
We got a new shouldParse(value, path) option in ParseJSONResultsPlugin for granular control of what gets JSON.parse'd and what stays a string using JSON paths.
import { JSONParseResultsPlugin } from 'kysely'
db.selectFrom('person')
.select((eb) => jsonArrayFrom(
eb.selectFrom('pet')
.where('pet.owner_id', '=', 'person.id')
.selectAll()
).as('pets'))
.withPlugin(new JSONParseResultsPlugin({
shouldParse: (_value, path) => {
// parse only the pets array
if (path.endsWith('."pets"')) {
return true
}
return false
}
}))
thenRef method in eb.case by @ericsodev in https://github.com/kysely-org/kysely/pull/1531whenRef(lhs, op, rhs) in eb.case. by @iam-abdul in https://github.com/kysely-org/kysely/pull/1598elseRef in eb.case() by @iam-abdul in https://github.com/kysely-org/kysely/pull/1601$pickTables, $omitTables and $extendTables, deprecate withTables. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1582SafeNullComparisonPlugin plugin by @rafaelalmeidatk in https://github.com/kysely-org/kysely/pull/1338ParseJSONResultsPlugin. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1453column and columns functions, deprecate their expression functions. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1664with(name, query). by @igalklebanov in https://github.com/kysely-org/kysely/pull/1702NarrowPartial by @ethanresnick in https://github.com/kysely-org/kysely/pull/1667ReadonlyKysely<DB> helper. by @igalklebanov in https://github.com/kysely-org/kysely/pull/218requireAllProps<T>(obj) usage with satisfies AllProps<T>. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1787FileMigrationProvider. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1661Migrator. by @jlucaso1 in https://github.com/kysely-org/kysely/pull/1480addIndex to CreateTableBuilder by @alenap93 in https://github.com/kysely-org/kysely/pull/1352datetime2 data type support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1792Migrator, FileMigrationProvider and other migration related things are now exported from 'kysely/migration'. Importing from 'kysely' will provide an informative error message at compilation time.
-import { Migrator, FileMigrationProvider } from 'kysely'
+import { Migrator, FileMigrationProvider } from 'kysely/migration'
Minimum TypeScript version is now 5.4. Versions 5.3 and older will get a very aggressive compilation error.
The library no longer ships CommonJS files. Use a Node.js version that supports require(esm), or use dynamic imports. ES Modules files have moved from /dist/esm/ to /dist/.
TypeScript build target was bumped to 'es2023'.
sql.value and sql.literal were removed after spending a long time in deprecation. Use sql.val and sql.lit instead.
db.executeQuery's queryId 2nd argument has been replaced with options?: AbortableQueryOptions after spending a long time in deprecation.
QueryResult.numUpdatedOrDeletedRows has been removed after spending a long time in deprecation. Dialects that use it need to be updated to use QueryResult.numAffectedRows instead.
UniqueConstraintNode.columns widened from ReadonlyArray<ColumnNode> to ReadonlyArray<OperationNode>.
ExpressionBuilder.withSchema has been removed after spending a long time in deprecation.
DatabaseIntrospector.getMetadata has been removed after spending a long time in deprecation. Use DatabaseIntrospector.getTables instead.
MssqlDialectConfig.Tedious.resetConnectionOnRelease has been removed after spending a long time in deprecation. Use MssqlDialectConfig.resetConnectionsOnRelease instead.
MssqlDialectConfig.Tarn.options.validateConnections has been removed after spending a long time in deprecation. Use MssqlDialectConfig.validateConnections instead.
InsertQueryNode.ignore has been removed after spending a long time in deprecation. Use InsertQueryNode.orAction instead.
PrimaryConstraintNode has been removed after spending a long time in deprecation. Use PrimaryKeyConstraintNode instead.
DropTablexNodeParams has been removed after spending a long time in deprecation. Use DropTableNodeParams instead.
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.17...v0.29.0
Hey 👋
This one's a banger! 💥 💥 💥
We got $pickTables, $omitTables compile-time helpers to narrow the world view of downstream queries, cutting down on compilation complexity/time while at it!
const results = await db
.$pickTables<'person' | 'pet'>() // <----- now `DB` is only { person: {...}, pet: {...} } for following methods.
.selectFrom('person')
.innerJoin('pet', 'pet.owner_id', 'person.id')
.selectAll()
.execute()
const results = await db
.$omitTables<'toy'>() // <----- now `DB` doesn't have a "toy" table description for following methods.
.selectFrom('person')
.innerJoin('pet', 'pet.owner_id', 'person.id')
.selectAll()
.execute()We got a new ReadonlyKysely<DB> helper type that turns your instance into a compile-time readonly instance!
import { Kysely } from 'kysely'
import type { ReadonlyKysely } from 'kysely/readonly'
export const db = new Kysely<Database>({...}) as never as ReadonlyKysely<Database>
db.selectFrom('person').selectAll() // no problem.
db.selectNoFrom(sql`now()`.as('now')) // no problem.
db.deleteFrom('person') // compilation error + deprecation!
db.insertInto('person').values({...}) // compilation error + deprecation!
db.mergeInto('person')... // compilation error + deprecation!
db.updateTable('person').set('first_name', 'Timmy') // compilation error + deprecation!
sql`...`.execute(db) // compilation error!
// etc. etc.We got a brand new PGlite dialect. With it comes a new supportsMultipleConnections adapter flag that uses a new centralized connection mutex when false - should help simplify all SQLite dialects out here!
import { PGlite } from '@electric-sql/pglite'
import { Kysely, PGliteDialect } from 'kysely'
const db = new Kysely<DB>({
// ...
dialect: new PGliteDialect({
pglite: new PGlite(),
}),
// ...
})We got $narrowType supporting nested narrowing and discriminated unions!
db.selectFrom('person_metadata')
.select(['discriminatedUnionProfile'])
// output type inferred as:
//
// {
// discriminatedUnionProfile: {
// auth:
// | { type: 'token'; token: string }
// | { type: 'session'; session_id: string }
// tags: string[]
// }
// }[]
.$narrowType<{ discriminatedUnionProfile: { auth: { type: 'token' } } }>()
// output type narrowed to:
//
// {
// discriminatedUnionProfile: {
// auth: { type: 'token'; token: string }
// tags: string[]
// }
// }[]
.execute()We got web standards driven query cancellation support. Pass an abort signal to execute* methods and similar. Pick between different inflight query abort strategies - ignore the query, cancel it on the database side or even kill the session on the database side.
import { Kysely, PostgresDialect } from 'kysely'
import { Client, ... } from 'pg'
const db = new Kysely<Database>({
dialect: new PostgresDialect({
// ...
controlClient: Client, // optional, for out-of-pool connections for database side query aborts.
// ...
})
})
const options = { signal: AbortSignal.timeout(3_000) } // throw abort/timeout errors and ignore query reuslts
query.execute(options)
query.stream(options)
sql`...`.execute(db, options)
db.executeQuery(compiledQuery, options)
// etc. etc.
query.execute({ ...options, inflightQueryAbortStrategy: 'cancel query' }) // also cancel query database side
query.execute({ ...options, inflightQueryAbortStrategy: 'kill session' }) // also kill session database sideWe got SafeNullComparisonPlugin to flip (in)equality operators to is and is not when right hand side argument is null.
import { Kysely, SafeNullComparisonPlugin } from 'kysely'
const db = new Kysely<DB>({
// ...
plugins: [new SafeNullComparisonPlugin()],
// ...
})
db.selectFrom('pet')
.where('name', '=', null) // outputs: "name" is null
.where('owner_id', '!=', null) // outputs: "owner_id" is not null
.selectAll()We got a new shouldParse(value, path) option in ParseJSONResultsPlugin for granular control of what gets JSON.parse'd and what stays a string using JSON paths.
import { JSONParseResultsPlugin } from 'kysely'
db.selectFrom('person')
.select((eb) => jsonArrayFrom(
eb.selectFrom('pet')
.where('pet.owner_id', '=', 'person.id')
.selectAll()
).as('pets'))
.withPlugin(new JSONParseResultsPlugin({
shouldParse: (_value, path) => {
// parse only the pets array
if (path.endsWith('."pets"')) {
return true
}
return false
}
}))thenRef method in eb.case by @ericsodev in #1531whenRef(lhs, op, rhs) in eb.case. by @iam-abdul in #1598elseRef in eb.case() by @iam-abdul in #1601$pickTables, $omitTables and $extendTables, deprecate withTables. by @igalklebanov in #1582SafeNullComparisonPlugin plugin by @rafaelalmeidatk in #1338ParseJSONResultsPlugin. by @igalklebanov in #1453column and columns functions, deprecate their expression functions. by @igalklebanov in #1664with(name, query). by @igalklebanov in #1702NarrowPartial by @ethanresnick in #1667ReadonlyKysely<DB> helper. by @igalklebanov in #218requireAllProps<T>(obj) usage with satisfies AllProps<T>. by @igalklebanov in #1787FileMigrationProvider. by @igalklebanov in #1661Migrator. by @jlucaso1 in #1480addIndex to CreateTableBuilder by @alenap93 in #1352datetime2 data type support. by @igalklebanov in #1792Migrator, FileMigrationProvider and other migration related things are now exported from 'kysely/migration'. Importing from 'kysely' will provide an informative error message at compilation time.
-import { Migrator, FileMigrationProvider } from 'kysely'
+import { Migrator, FileMigrationProvider } from 'kysely/migration'Minimum TypeScript version is now 5.4. Versions 5.3 and older will get a very aggressive compilation error.
The library no longer ships CommonJS files. Use a Node.js version that supports require(esm), or use dynamic imports. ES Modules files have moved from /dist/esm/ to /dist/.
TypeScript build target was bumped to 'es2023'.
sql.value and sql.literal were removed after spending a long time in deprecation. Use sql.val and sql.lit instead.
db.executeQuery's queryId 2nd argument has been replaced with options?: AbortableQueryOptions after spending a long time in deprecation.
QueryResult.numUpdatedOrDeletedRows has been removed after spending a long time in deprecation. Dialects that use it need to be updated to use QueryResult.numAffectedRows instead.
UniqueConstraintNode.columns widened from ReadonlyArray<ColumnNode> to ReadonlyArray<OperationNode>.
ExpressionBuilder.withSchema has been removed after spending a long time in deprecation.
DatabaseIntrospector.getMetadata has been removed after spending a long time in deprecation. Use DatabaseIntrospector.getTables instead.
MssqlDialectConfig.Tedious.resetConnectionOnRelease has been removed after spending a long time in deprecation. Use MssqlDialectConfig.resetConnectionsOnRelease instead.
MssqlDialectConfig.Tarn.options.validateConnections has been removed after spending a long time in deprecation. Use MssqlDialectConfig.validateConnections instead.
InsertQueryNode.ignore has been removed after spending a long time in deprecation. Use InsertQueryNode.orAction instead.
PrimaryConstraintNode has been removed after spending a long time in deprecation. Use PrimaryKeyConstraintNode instead.
DropTablexNodeParams has been removed after spending a long time in deprecation. Use DropTableNodeParams instead.
Full Changelog: v0.28.17...v0.29.0
db.deleteFrom('person') // compilation error + deprecation! db.insertInto('person').values({...}) // compilation error + deprecation! db.mergeInto('pe…
Hey 👋
This one's a banger! 💥 💥 💥
pnpm i kysely@next
We got $pickTables, $omitTables compile-time helpers to narrow the world view of downstream queries, cutting down on compilation complexity/time while at it!
const results = await db
.$pickTables<'person' | 'pet'>() // <----- now `DB` is only { person: {...}, pet: {...} } for following methods.
.selectFrom('person')
.innerJoin('pet', 'pet.owner_id', 'person.id')
.selectAll()
.execute()
const results = await db
.$omitTables<'toy'>() // <----- now `DB` doesn't have a "toy" table description for following methods.
.selectFrom('person')
.innerJoin('pet', 'pet.owner_id', 'person.id')
.selectAll()
.execute()
We got a new ReadonlyKysely<DB> helper type that turns your instance into a compile-time readonly instance!
import { Kysely } from 'kysely'
import type { ReadonlyKysely } from 'kysely/readonly'
export const db = new Kysely<Database>({...}) as never as ReadonlyKysely<Database>
db.selectFrom('person').selectAll() // no problem.
db.selectNoFrom(sql`now()`.as('now')) // no problem.
db.deleteFrom('person') // compilation error + deprecation!
db.insertInto('person').values({...}) // compilation error + deprecation!
db.mergeInto('person')... // compilation error + deprecation!
db.updateTable('person').set('first_name', 'Timmy') // compilation error + deprecation!
sql`...`.execute(db) // compilation error!
// etc. etc.
We got a brand new PGlite dialect. With it comes a new supportsMultipleConnections adapter flag that uses a new centralized connection mutex when false - should help simplify all SQLite dialects out here!
import { PGlite } from '@electric-sql/pglite'
import { Kysely, PGliteDialect } from 'kysely'
const db = new Kysely<DB>({
// ...
dialect: new PGliteDialect({
pglite: new PGlite(),
}),
// ...
})
We got $narrowType supporting nested narrowing and discriminated unions!
db.selectFrom('person_metadata')
.select(['discriminatedUnionProfile'])
// output type inferred as:
//
// {
// discriminatedUnionProfile: {
// auth:
// | { type: 'token'; token: string }
// | { type: 'session'; session_id: string }
// tags: string[]
// }
// }[]
.$narrowType<{ discriminatedUnionProfile: { auth: { type: 'token' } } }>()
// output type narrowed to:
//
// {
// discriminatedUnionProfile: {
// auth: { type: 'token'; token: string }
// tags: string[]
// }
// }[]
.execute()
We got web standards driven query cancellation support. Pass an abort signal to execute* methods and similar. Pick between different inflight query abort strategies - ignore the query, cancel it on the database side or even kill the session on the database side.
import { Kysely, PostgresDialect } from 'kysely'
import { Client, ... } from 'pg'
const db = new Kysely<Database>({
dialect: new PostgresDialect({
// ...
controlClient: Client, // optional, for out-of-pool connections for database side query aborts.
// ...
})
})
const options = { signal: AbortSignal.timeout(3_000) } // throw abort/timeout errors and ignore query reuslts
query.execute(options)
query.stream(options)
sql`...`.execute(db, options)
db.executeQuery(compiledQuery, options)
// etc. etc.
query.execute({ ...options, inflightQueryAbortStrategy: 'cancel query' }) // also cancel query database side
query.execute({ ...options, inflightQueryAbortStrategy: 'kill session' }) // also kill session database side
We got SafeNullComparisonPlugin to flip (in)equality operators to is and is not when right hand side argument is null.
import { Kysely, SafeNullComparisonPlugin } from 'kysely'
const db = new Kysely<DB>({
// ...
plugins: [new SafeNullComparisonPlugin()],
// ...
})
db.selectFrom('pet')
.where('name', '=', null) // outputs: "name" is null
.where('owner_id', '!=', null) // outputs: "owner_id" is not null
.selectAll()
We got a new shouldParse(value, path) option in ParseJSONResultsPlugin for granular control of what gets JSON.parse'd and what stays a string using JSON paths.
import { JSONParseResultsPlugin } from 'kysely'
db.selectFrom('person')
.select((eb) => jsonArrayFrom(
eb.selectFrom('pet')
.where('pet.owner_id', '=', 'person.id')
.selectAll()
).as('pets'))
.withPlugin(new JSONParseResultsPlugin({
shouldParse: (_value, path) => {
// parse only the pets array
if (path.endsWith('.pets')) {
return true
}
return false
}
}))
thenRef method in eb.case by @ericsodev in https://github.com/kysely-org/kysely/pull/1531whenRef(lhs, op, rhs) in eb.case. by @iam-abdul in https://github.com/kysely-org/kysely/pull/1598elseRef in eb.case() by @iam-abdul in https://github.com/kysely-org/kysely/pull/1601$pickTables, $omitTables and $extendTables, deprecate withTables. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1582SafeNullComparisonPlugin plugin by @rafaelalmeidatk in https://github.com/kysely-org/kysely/pull/1338ParseJSONResultsPlugin. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1453column and columns functions, deprecate their expression functions. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1664with(name, query). by @igalklebanov in https://github.com/kysely-org/kysely/pull/1702NarrowPartial by @ethanresnick in https://github.com/kysely-org/kysely/pull/1667ReadonlyKysely<DB> helper. by @igalklebanov in https://github.com/kysely-org/kysely/pull/218requireAllProps<T>(obj) usage with satisfies AllProps<T>. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1787FileMigrationProvider. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1661Migrator. by @jlucaso1 in https://github.com/kysely-org/kysely/pull/1480addIndex to CreateTableBuilder by @alenap93 in https://github.com/kysely-org/kysely/pull/1352datetime2 data type support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1792Migrator, FileMigrationProvider and other migration related things are now exported from 'kysely/migration'. Importing from 'kysely' will provide an informative error message at compilation time.
-import { Migrator, FileMigrationProvider } from 'kysely'
+import { Migrator, FileMigrationProvider } from 'kysely/migration'
Minimum TypeScript version is now 5.4. Versions 5.3 and older will get a very aggressive compilation error.
The library no longer ships CommonJS files. Use a Node.js version that supports require(esm), or use dynamic imports. ES Modules files have moved from /dist/esm/ to /dist/.
TypeScript build target was bumped to 'es2023'.
sql.value and sql.literal were removed after spending a long time in deprecation. Use sql.val and sql.lit instead.
db.executeQuery's queryId 2nd argument has been replaced with options?: AbortableQueryOptions after spending a long time in deprecation.
QueryResult.numUpdatedOrDeletedRows has been removed after spending a long time in deprecation. Dialects that use it need to be updated to use QueryResult.numAffectedRows instead.
UniqueConstraintNode.columns widened from ReadonlyArray<ColumnNode> to ReadonlyArray<OperationNode>.
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.16...v0.29.0-rc.0
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
0.29 is right around the corner. Try the latest RC version!
.key(...) and .at(...) against SQL injections and exfiltrations. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1804Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.16...v0.28.17
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
0.29 is right around the corner. Try the latest RC version!
.key(...) and .at(...) against SQL injections and exfiltrations. by @igalklebanov in #1804Full Changelog: v0.28.16...v0.28.17
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
0.29 is getting closer btw. 🌶️
FilterObject allows any defined value when query context has no tables (TB is never). by @igalklebanov in https://github.com/kysely-org/kysely/pull/1791verifyDepsBeforeRun to "prompt". by @igalklebanov in https://github.com/kysely-org/kysely/commit/20548bca896ea6907f584cad7677974f97205148Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.15...v0.28.16
The introduction of dehydration in JSON functions/helpers caused an unexpected bug for consumers that have some columns defined as '${number}', e.g. '
Hey 👋
The introduction of dehydration in JSON functions/helpers caused an unexpected bug for consumers that have some columns defined as '${number}', e.g. '1' | '2' (also when wrapped in ColumnType or similar). Such columns, when participating in a JSON function/helper would dehydrate to number instead of staying as string.
Why dehydrate numeric strings to numbers in the first place? Select types in kysely describe the data after underlying driver's (e.g. pg) data transformation. Some drivers transform numeric columns to strings to be safe. When these columns participate in JSON functions, they lose original column data types - drivers don't know they need to transform to string - they return as-is.
This release introduces a special helper type that wraps your column type definition and tells kysely to NOT dehydrate it in JSON functions/helpers.
import type { NonDehydrateable } from 'kysely'
interface Database {
my_table: {
a_column: '1' | '2' | '3', // dehydrates to `number`
another_column: NonDehydrateable<'1' | '2' | '3'>, // stays `'1' | '2' | '3'`
column_too: NonDehydrateable<ColumnType<'1' | '2' | '3'>> // stays `'1' | '2' | '3'`
}
}
NonDehydrateable<T> to allow opt-out from dehydration in JSON functions/helpers. by @igalklebanov in #1697Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.14...v0.28.15
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
\\') are used. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1754 & https://github.com/kysely-org/kysely/commit/054e80174c618bc1ff8896e8557631e2be133659Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.13...v0.28.14
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
sideEffects: false in root package.json resulting in bigger bundles in various bundlers. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1746Insertable allows non-objects when a table has no required columns. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1747ON COMMIT clause not being output when using .as(query) in CREATE TABLE queries. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1748tsconfig.json for TypeScript native. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1749Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.12...v0.28.13
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
eb.ref(col, '->$').key(key) is injectable. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1727mysql2@v3.18.2 support #1722 by @fenichelar in https://github.com/kysely-org/kysely/pull/1729Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.11...v0.28.12
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.10...v0.28.11
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
ExtractColumnType and DrainOuterGeneric type exports by @mifi in https://github.com/kysely-org/kysely/pull/1679$narrowType compilation errors when composite: true. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1681executeTakeFirst compilation error when composite. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1683with/withRecursive compilation errors when composite. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1684if not exists. by @austin-hall-skylight in https://github.com/kysely-org/kysely/pull/1608returning compilation errors when composite. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1682pnpm to 10.26.1, use allowBuilds and blockExoticSubdeps. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1663Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.9...v0.28.10
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.8...v0.28.9
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.7...v0.28.8
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
eb(). by @igalklebanov in https://github.com/kysely-org/kysely/pull/1579Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.6...v0.28.7
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Docs site has been optimized and all we got was this animation:
<img width="558" height="209" alt="image" src="https://github.com/user-attachments/assets/c155839d-7e94-4e76-8d74-0d4a048ce8fd" />
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.5...v0.28.6
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Buffer breaking ShallowDehydrateValue in non-Node.js TypeScript environments. by @igalklebanov in #1542.Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.4...v0.28.5
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.3...v0.28.4
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Hey 👋
A small batch of bug fixes. Please report any issues. 🤞😰🤞
Kysely<any> type errors with narrow table name types by @koskimas in https://github.com/kysely-org/kysely/pull/1443AsyncDisposable usage erroring for older TypeScript versions. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1507Dates and other JS/Node-native instances that require data type metadata. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1477Full Changelog: https://github.com/kysely-org/kysely/compare/0.28.2...v0.28.3
fix: SQLite's introspector is printing deprecation errors for orderBy(array). by @igalklebanov in https://github.com/kysely-org/kysely/pull/1435
Hey 👋
v0.28 broke an undocumented TypeScript behavior our API had that allowed you to pass table name unions to query builders and enable some DRYing of queries. Seeing that this pattern was quite popular, we decided to support it officially with the addition of the table method in the dynamic module.
You can pull off some crazy complex stuff like:
async function getRowByColumn<
T extends keyof Database,
C extends keyof Database[T] & string,
V extends SelectType<Database[T][C]>,
>(t: T, c: C, v: V) {
// We need to use the dynamic module since the table name
// is not known at compile time.
const { table, ref } = db.dynamic
return await db
.selectFrom(table(t).as('t'))
.selectAll()
.where(ref(c), '=', v)
// `id` can be directly referenced since every table has it.
.orderBy('t.id')
.executeTakeFirstOrThrow()
}
const person = await getRowByColumn('person', 'first_name', 'Arnold')
...and it'll narrow the downstream query context to the intersection of all the possible shapes of tables in the union type. (DONT DO THIS AT HOME KIDS!)
A simpler example would be:
async function deleteItem(id: string, table: 'person' | 'pet') {
await db
.deleteFrom(db.dynamic.table(table).as('t'))
.where('id', '=', id)
.executeTakeFirstOrThrow()
}
If you attempt to refer to a column that doesn't exist in both "person" and "pet" (e.g. "pet"'s "species" column), the compiler will correctly yell at you.
table to DynamicModule for dynamic table references by @koskimas in https://github.com/kysely-org/kysely/pull/1434orderBy(array). by @igalklebanov in https://github.com/kysely-org/kysely/pull/1435Full Changelog: https://github.com/kysely-org/kysely/compare/0.28.1...0.28.2
Just a small crucial bug fix release. Please inform us if you see any more regressions since v0.28. 🙏
Hey 👋
Just a small crucial bug fix release. Please inform us if you see any more regressions since v0.28. 🙏
Full Changelog: https://github.com/kysely-org/kysely/compare/0.28.0...0.28.1
revisiting orderBy - deprecations, new order by item builder (nullFirst(), nullsLast(), collate()). by @igalklebanov in https://github.com/kysely-org/…
Hey 👋
Transactions are getting a lot of love in this one!
As part an effort to replace Knex with Kysely, B4nan, the author of mikro-orm drove the new setAccessMode('read only'|'read write') method when starting transactions.
You can now commit/rollback transactions manually and there's even savepoint support:
const trx = await db.startTransaction().execute()
try {
// do stuff with `trx`, including work with savepoints via the new `savepoint(name)`, `rollbackToSavepoint(name)` and `releaseSavepoint(name)` methods!
await trx.commit().execute()
} catch (error) {
await trx.rollback().execute()
throw error
}
We also added using keyword support, so now you can write:
await using db = new Kysely({...})
and db.destroy() will be called automatically once the current scope is exited.
If you plan on trying this out (it is optional, you can still const db = new Kysely({...}) and await db.destroy() manually), the using keyword requires typescript >= 5.2 and the following tsconfig.json options:
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ESNext", ...],
...
}
...
}
We also added a plugin to handle in () and not in (). It comes with 2 handling strategies, one similar to how Knex.js, PrismaORM, Laravel and SQLAlchemy do it, and one similar to how TypeORM and Sequelize do it. It also supports custom strategies, e.g. throwing an error to avoid making a call to the database and wasting resources. Here's an example with one of the strategies we ship:
import {
// ...
HandleEmptyInListsPlugin,
// ...
replaceWithNoncontingentExpression,
// ...
} from 'kysely'
const db = new Kysely<Database>({
// ...
plugins: [
new HandleEmptyInListsPlugin({
strategy: replaceWithNoncontingentExpression
})
],
})
// ...
.where('id', 'in', [])
.where('first_name', 'not in', []) // => `where 1 = 0 and 1 = 1`
InferResult should output plural. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1064ControlledTransaction. by @igalklebanov in https://github.com/kysely-org/kysely/pull/962 & https://github.com/kysely-org/kysely/pull/1193await using kysely = new Kysely() support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1167queryId to CompiledQuery and all transformer methods. by @igalklebanov in https://github.com/kysely-org/kysely/pull/176returning support in MERGE queries. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1171validateConnections and resetConnectionsOnRelease to root of config, flip default resetConnectionsOnRelease behavior. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1388InferResult now outputs InsertResult[], UpdateResult[], DeleteResult[], MergeResult[], instead of InsertResult, UpdateResult, DeleteResult, MergeResult. To get the singular form, use type Result = InferResult<T>[number].QueryCreator's methods should no longer pass type checks. We never supported these officially.preventAwait is now removed on all builders, you must avoid awaiting builders without calling execute-like methods on your own.QueryResult.numUpdatedOrDeletedRows has been removed (after spending ~2 years in deprecation). We still log a warning. Outdated dialects that don't use QueryResult.numAffectedRows should be updated OR forked.DefaultQueryExecutor.compileQuery now requires passing a queryId argument. Use the newly exported createQueryId() as that argument value from now on.UpdateValuesNode type has been removed.MssqlDialectConfig.tedious.resetConnectionOnRelease has been deprecated, and had it's default flipped to false. Use MssqlDialectConfig.resetConnectionsOnRelease instead.MssqlDialectConfig.tarn.options.validateConnections has been deprecated. Use MssqlDialectConfig.validateConnections instead.' injection protected, hopefully. Please report any issues.Full Changelog: https://github.com/kysely-org/kysely/compare/0.27.6...0.28.0
v0.28 is right around the corner! 👀
Hey 👋
v0.28 is right around the corner! 👀
Full Changelog: https://github.com/kysely-org/kysely/compare/0.27.5...0.27.6
Long-time community member and ambassador @thelinuxlich has joined the contributors club! 🏅
Hey 👋
Long-time community member and ambassador @thelinuxlich has joined the contributors club! 🏅
v0.28 is right around the corner! 👀
onReserveConnection to Postgres and MySQL dialect configs by @dcousineau in https://github.com/kysely-org/kysely/pull/996generatedAlwaysAs by @nikeee in https://github.com/kysely-org/kysely/pull/1113MERGE examples by @igalklebanov in https://github.com/kysely-org/kysely/pull/1188Full Changelog: https://github.com/kysely-org/kysely/compare/0.27.4...0.27.5
We've reached 100 contributors AND 1,000 pull requests since our last release! 🍾 Here's all the amazing work done since version 0.27.3...
Hey 👋
We've reached 100 contributors AND 1,000 pull requests since our last release! 🍾 Here's all the amazing work done since version 0.27.3...
clearGroupBy() by @dswbx in https://github.com/kysely-org/kysely/pull/921objectStrategy option that allows to not mutate result objects/arrays @ ParseJSONResultsPlugin. by @igalklebanov in https://github.com/kysely-org/kysely/pull/953OUTPUT clause support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/828preventAwait to alter-column-builder.ts. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1031eb in selectFrom(eb => ...) is wrong by @koskimas in https://github.com/kysely-org/kysely/commit/873671b758fd70679f440057595399d73813c0ccWhenNodes with a space by @gittgott in https://github.com/kysely-org/kysely/pull/940InferResult not working for merge queries. by @igalklebanov in https://github.com/kysely-org/kysely/pull/902MssqlDialect streaming not handling backpressure. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1041MssqlDriver. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1042tedious support in Bun by @igalklebanov in https://github.com/kysely-org/kysely/pull/1018kysely-ctl in migrations section. by @igalklebanov in https://github.com/kysely-org/kysely/pull/1035UpdateResult by @movahhedi in https://github.com/kysely-org/kysely/pull/993Full Changelog: https://github.com/kysely-org/kysely/compare/0.27.3...0.27.4
This release happened on 03/09/2024.
Hey 👋
This release happened on 03/09/2024.
cast method to ExpressionBuilder. by @koskimas in https://github.com/kysely-org/kysely/commit/3df726fd566664a1842d0fe8cfc0d79983647e39ExtractTableAlias exposed by TypeScript 5.4. by @koskimas in https://github.com/kysely-org/kysely/commit/e356951905cf21b3da0e8071eaae80c6643823d1MERGE query support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/700where) by @MarkusWendorf in https://github.com/kysely-org/kysely/pull/883IDENTITY column support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/823LIMIT operator for update statements by @tbui17 in https://github.com/kysely-org/kysely/pull/885FETCH clause support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/822TOP clause support. by @igalklebanov in https://github.com/kysely-org/kysely/pull/821into is now optional in InsertQueryNode.table is now optional in UpdateQueryNode.sql template tag.Full Changelog: https://github.com/kysely-org/kysely/compare/0.27.2...0.27.3
Add allowUnorderedMigrations option for the migrator. #723 Awesome work by @tracehelms ❤️
allowUnorderedMigrations option for the migrator. #723 Awesome work by @tracehelms ❤️Kysely<any>.UpdateQueryBuilder#set and InsertQueryBuilder#values methods.Support for update of table and friends #683
$notNull type helperfor update of table and friends #683insert into "person" default values #685limit and offsetfn.agg regression where two type arguments were required #829Deprecated functions eb.cmpr and eb.bxp have been removed. Use eb as a function instead.
json_agg and to_json functions to function moduleis distinct from operator #673set('first_name', 'Jennifer') variant for update query's set method #672as statement support for createTable #771. Thank you @viraxslot ❤️nulls not distinct option for constraints #770. Thank you @viraxslot ❤️addIndex & dropIndex @ AlterTableBuilder #720. Thank you @Gasperostream() support for sqlite dialect #754. Thank you @tgriesser ❤️$if #793. Thank you @igalklebanov ❤️onConflict..doUpdateSet used select types instead of update types. #792. Thank you @igalklebanov ❤️eb.jsonPath<$> #791. Thank you @igalklebanov ❤️$narrowType supports new type tag NotNull for an easier way to mark columns not nullable manuallymin and max aggregate functions.selectNoFrom is removed from ExpressionBuilder due to severe typescript performance issues. selectNoFrom still exists in the Kysely instance, and in most cases, you can use that instead. See this example on how to migrate: https://kyse.link/?p=s&i=sqAZIvTQktxgXYzHGkqX.where('first_name', '=', sql`something`). You need to explicitly give a type for sql expressions like this sql<string>`something` eb.cmpr and eb.bxp have been removed. Use eb as a function instead.Type performance improvements. We got ~30% speedup in our type test suite. Results will vary.
select(eb => [autocompletion works here now]).Added support for select statements without a from clause. The function is called selectNoFrom. The function name was selected after a lot of discussi
from clause. The function is called selectNoFrom. The function name was selected after a lot of discussion. The most natural name would just be select, but new users would find that in a list of autocompletions before selectFrom and naturally use it when trying to create a select from query. This would be especially true for people coming from knex where a select from query is started using a select call. #605and and or functions. Allows easy where(eb => eb.and(object)) filters. #583any function to function module. #612between method to expression builder. #602lit method to expression builder. #600orderBy. #423 Thank you @igalklebanov ❤️An example of an object and call:
const persons = await db
.selectFrom('person')
.selectAll()
.where((eb) => eb.and({
first_name: 'Jennifer',
last_name: eb.ref('first_name')
}))
.execute()
select * from "person"
where "first_name" = $1 and "last_name" = "first_name"
Nothing published for this version
…discord discussions. Unfortunately this means deprecating the recently added cmpr and bxp methods, but the migration should be painless. Read more @ #…
We improved the expression builder based on excellent feedback from the community in this issue in addition to many discord discussions. Unfortunately this means deprecating the recently added cmpr and bxp methods, but the migration should be painless. Read more @ #565.
Before you could create comparisons and arbitrary binary expressions using cmpr and bxp respectively:
where((eb) => eb.or([
eb.cmpr('first_name', '=', 'Jennifer'),
eb.cmpr('first_name', '=', 'Sylvester'),
]))
set((eb) => ({
age: eb.bxp('age', '+', 1)
}))
After this release, you'd do this instead:
where((eb) => eb.or([
eb('first_name', '=', 'Jennifer'),
eb('first_name', '=', 'Sylvester'),
]))
set((eb) => ({
age: eb('age', '+', 1)
}))
As you can see we made the expression builder callable and it can create all kinds of binary expressions. You can still use destructuring as before since the expression builder has a new property eb that returns itself:
where(({ eb, or }) => or([
eb('first_name', '=', 'Jennifer'),
eb('first_name', '=', 'Sylvester'),
]))
or and and chainingWe've also added new way to create and and or expressions using chaining
where((eb) =>
eb('first_name', '=', 'Jennifer').or('first_name', '=', 'Sylvester')
]))
The old and and or methods are still there and are not going anywhere.
The expression builder's ref function can now be used to reference nested JSON columns' fields and array items in a type-safe way:
// Postgres syntax: "addresses"->0->'postalCode'
where(({ eb, ref }) =>
eb(ref('addresses', '->').at(0).key('postalCode'), '=', '61710')
)
// MySQL syntax: `addresses`->'$[0].postalCode'
where(({ eb, ref }) =>
eb(ref('addresses', '->$').at(0).key('postalCode'), '=', '61710')
)
The JSON reference builder is just our first guess of a good API. We're eager to hear your feedback. More examples and a recipe on the subject will follow shortly after this release. Read more @ #440.
Large amount of contributions from many awesome people in this one, but one definitely stands out:
Large amount of contributions from many awesome people in this one, but one definitely stands out:
Using his sorcerous knowledge of the typescript compiler internals @schusovskoy was able to significantly reduce the possibility of the notorious Type instantiation is excessively deep and possibly infinite compiler error throughout Kysely. Check out the PR here #483 🧙. In our typing tests, we were able to at least double the complexity of the troublesome queries without hitting slowdowns or compiler errors. In some cases the issue seems to have gone away completely.
Simply amazing work. Thank you so much @schusovskoy ❤️
Other fixes and improvements in no particular order:
case when then end builder #404. Thanks @igalklebanov ❤️$narrowType helper for narrowing the query output type #380. Thanks @igalklebanov ❤️agg method to expression builder for arbitrary aggregate function calls #417 @igalklebanov ❤️$if method should no longer cause performance issues or excessively deep typesIn addition to this there were small fixes from multiple awesome people including:
Add mysql helper module with jsonArrayFrom and jsonObjectFrom functions. See this recipe for more info.
jsonArrayFrom and jsonObjectFrom functions. See this recipe for more info.Nothing published for this version
So much new stuff and big improvements, I don't know where to start! 🎉. There should be no breaking changes, but with this amount of changes and new f…
So much new stuff and big improvements, I don't know where to start! 🎉. There should be no breaking changes, but with this amount of changes and new features, it's always possible we've broken something 😬. As always, please open an issue if something is broken.
Let's start with the reason some of you are here: the deprecated filter methods and the improved ExpressionBuilder:
ExpressionBuilderWe've deprecated most of the where, having, on and other filter methods like whereExists, whereNotExists, orWhere, orWhereExists in favour of the new expression builder. To get an idea what the expression builder is and what it can do, you should take a look at this recipe. Here are some of the most common migrations you should do:
// Old
where(eb => eb
.where('first_name', '=', 'Jennifer')
.orWhere('last_name', '=', 'Aniston')
)
// New
where(({ or, cmpr }) => or([
cmpr('first_name', '=', 'Jennifer'),
cmpr('last_name', '=', 'Aniston')
]))
// Old
whereNotExists(eb => eb
.selectFrom('pet')
.select('pet.id')
.whereRef('pet.owner_id', '=', 'person.id')
)
// New
where(({ not, exists, selectFrom }) => not(exists(
selectFrom('pet')
.select('pet.id')
.whereRef('pet.owner_id', '=', 'person.id')
)))
You can fine more examples here and here.
The first version of kysely.dev is out 🎉 A huge thanks to @fhur for the initiative and for doing allmost all work on that ❤️
Now that the site is out, we'll concentrate on adding more documentation and examples there. For now, it's pretty minimal.
returningAll('table') overload for DeleteQueryBuilder. Thank you @anirudh1713 ❤️ #314update, insert and delete query results on postgres. Thank you @igalklebanov ❤️ #377where method toCreateIndexBuilder. Thank you @igalklebanov ❤️ #371kysely/helpers/postgres for some postgres-spcific higher level helpers. Similar packages will be added for other dialects too in the future. See this recipe for the newly available helpers.Force IDEs to show simple result types on hover
<img width="382" alt="Screenshot 2023-03-06 at 11 39 06" src="https://user-images.githubusercontent.com/846508/223072962-04ca154e-7626-4deb-a1de-3345bd25a102.png">
Thank you @steida for pointing me to the Simplify helper.
Pass options to dialect adapter migration lock methods (not a breaking change).
ifNotExists for CreateIndexBuilder #253using clause support for DeleteQueryBuilder #241. Thank you @igalklebanov ❤️match to the list of supported comparison operators #280. Thank you @jonluca ❤️Fix regression bug where comparing non-nullable and nullable values weren't allowed by the types in where, having and other comparison methods.
where, having and other comparison methods.Add the assertType method for dealing with Type instantiation is excessively deep and possibly infinite errors.
Type instantiation is excessively deep and possibly infinite errors.clearSelect, clearWhere etc. methods. Thank you @wirekang ❤️Nothing published for this version
So many fixes and features in this one. @igalklebanov has been on fire 🔥. Almost all of these are his awesome work.
So many fixes and features in this one. @igalklebanov has been on fire 🔥. Almost all of these are his awesome work.
ArrayBuffer usage with CamelCasePlugin #193. Thank you @igalklebanov ❤️fn.coalesce helper #179. Thank you @igalklebanov ❤️exactOptionalPropertyTypes typescript setting #210. Thank you @igalklebanov ❤️sql in distinctOn #239. Thank you @naorpeled ❤️alter table query #238. Thank you @naorpeled ❤️call method to create/alter table statement builders #242. Thank you @jacobpgn ❤️sql expressions or the RawBuilder class, you may need to specify a type for the expression like this:sql<string>`something`
Before:
await db.schema
.alterTable('person')
.alterColumn('first_name')
.setDataType('text')
.execute();
After:
await db.schema
.alterTable('person')
.alterColumn('first_name', (ac) => ac.setDataType('text'))
.execute()
Add better aggregate function builder. Thank you @igalklebanov ❤️
CreateIndexBuilder used to invalidly add two sets of parentheses in some cases. For example, before you could write a query like this:
db.schema
.createIndex('idx')
.on('table')
.expression('a < 10')
and it worked because Kysely added the needed double parentheses for that particular case. The problem is that not all expressions should have double parentheses and the expression method shouldn't add the second set.
If you've used db.schema.createIndex with a custom expression you may need to add the extra set of parentheses depending on the query (check the database docs). For example in case of our example, you'll need to change it into:
db.schema
.createIndex('idx')
.on('table')
.expression('(a < 10)')
Start using default instead of null for missing values in multi-row inserts on supported dialects.
default instead of null for missing values in multi-row inserts on supported dialects.Enable returning for sqlite. Thank you @waynebloss ❤️
returning for sqlite. Thank you @waynebloss ❤️Add cascade method to drop table, drop schema, drop view and drop index builders. Thank you @jaym910 ❤️
cascade method to drop table, drop schema, drop view and drop index builders. Thank you @jaym910 ❤️Nothing published for this version
Fixes #135. Thank you @68kHeart ❤️
Nothing published for this version
Fix corner case bugs in withSchema
withSchemaThe internal "operation node tree" changed a little bit. This only affects you if you've implemented a custom plugin or are doing something funky with the node tree. The only change is the new node SchemableIdentifier that's used by TableNode and a small set of other nodes that can have a schema.
* Fixes #131 * Exports WithSchemaPlugin
WithSchemaPluginAdds support for explaining queries. Thank you @igalklebanov
CreateTableBuilder. Thank you @igalklebanovYour coding agent can read these notes before it upgrades. Set up the MCP server →