Download Latest Version 0.29.4 source code.zip (15.3 MB)
Email in envelope

Get an email when there's a new version of Kysely SQL

Home / v0.29.0
Name Modified Size InfoDownloads / Week
Parent folder
0.29.0 source code.tar.gz 2026-05-08 15.0 MB
0.29.0 source code.zip 2026-05-08 15.3 MB
README.md 2026-05-08 13.4 kB
Totals: 3 Items   30.3 MB 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!

:::ts
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!

:::ts
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!

:::ts
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!

:::ts
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.

:::ts
  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.

:::ts
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.

:::ts
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
    } 
  }))

๐Ÿš€ Features

PostgreSQL ๐Ÿ˜ / MySQL ๐Ÿฌ

PostgreSQL ๐Ÿ˜ / MSSQL ๐Ÿฅ…

PostgreSQL ๐Ÿ˜

MySQL ๐Ÿฌ

MSSQL ๐Ÿฅ…

PGlite ๐ŸŸจ

๐Ÿž Bugfixes

๐Ÿ“– Documentation

๐Ÿ“ฆ CICD & Tooling

โš ๏ธ Breaking Changes

  • Migrator, FileMigrationProvider and other migration related things are now exported from 'kysely/migration'. Importing from 'kysely' will provide an informative error message at compilation time.

diff -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>.

๐Ÿค New Contributors

Full Changelog: https://github.com/kysely-org/kysely/compare/v0.28.17...v0.29.0

Source: README.md, updated 2026-05-08