Use Bun's native high-performance SQLite driver (bun:sqlite) with Knex.js - 3-6x faster than node-sqlite3
npm install knex-bun-sqliteUse Bun's native high-performance SQLite driver (bun:sqlite) with Knex.js.
⥠3-6x faster than node-sqlite3 while keeping all of Knex's elegant query builder API!
- ð Much Faster: Bun's native SQLite is 3-6x faster than node-sqlite3
- ðŊ Drop-in Replacement: Works with existing Knex code
- ðŠķ Zero Native Dependencies: No need to compile native addons
- âĻ Clean API: Use Knex's query builder with Bun's speed
``bash`
bun add knex-bun-sqlite knex
> Note: This package requires Bun runtime (v1.0.0+). It uses bun:sqlite which is only available in Bun.
Create a reusable database module for your application - this is the best practice:
`javascript
// db.js
const knex = require('knex')({
client: require('knex-bun-sqlite'), // Clean and simple!
connection: { filename: './mydb.sqlite' },
useNullAsDefault: true
})
module.exports = knex
`
Then in your app:
`javascript
const db = require('./db')
// Use Knex normally
const movies = await db('movies').where('year', '>', 2000).select('*')
await db.destroy()
`
If you prefer, you can also use module interception to replace sqlite3 automatically:
`javascript
const KnexBunSqlite = require('knex-bun-sqlite')
// Intercept sqlite3 module loading
const Module = require('module')
const originalRequire = Module.prototype.require
Module.prototype.require = function(id) {
if (id === 'sqlite3') {
return KnexBunSqlite.Database // Use the adapter
}
return originalRequire.apply(this, arguments)
}
// Now use Knex normally - it will use bun:sqlite under the hood!
const knex = require('knex')({
client: 'sqlite3',
connection: {
filename: './mydb.sqlite'
},
useNullAsDefault: true
})
// All your queries work exactly the same!
async function example() {
const users = await knex('users').select('*')
console.log(users)
await knex.destroy()
}
example()
`
All Knex operations are fully supported:
- â
SELECT queries with WHERE, JOIN, ORDER BY, LIMIT, etc.
- â
INSERT, UPDATE, DELETE operations
- â
Transactions
- â
Query builder methods
- â
Raw queries
- â
Connection pooling
- â
Proper cleanup with .destroy()
- â
Schema migrations (via SQLite3 in knexfile for CLI, bun:sqlite in your app)
`javascript
const db = require('./db') // Your setup from above
// SELECT
const users = await db('users')
.where('age', '>', 18)
.orderBy('name')
.select('*')
// INSERT
await db('users').insert({
name: 'Alice',
email: 'alice@example.com'
})
// UPDATE
await db('users')
.where('id', 1)
.update({ email: 'newemail@example.com' })
// DELETE
await db('users').where('inactive', true).del()
// Always clean up!
await db.destroy()
`
For Knex CLI migrations (running bun knex migrate:latest), use SQLite3 in your knexfile since Knex itself will invoke the SQLite driver:
`javascript`
// knexfile.js - For Knex CLI migrations
module.exports = {
development: {
client: 'sqlite3', // Use standard sqlite3 for CLI
connection: {
filename: './dev.sqlite3'
},
useNullAsDefault: true
}
}
Then run migrations with Knex:
`bash`
knex migrate:latest
knex migrate:rollback
knex seed:run
For your application code, use the reusable database module with knex-bun-sqlite (as shown in Method 1) to get the performance benefits of bun:sqlite while using the same database:
`javascript
// db.js - Your application's database connection
const knex = require('knex')({
client: require('knex-bun-sqlite'), // Use bun:sqlite for speed!
connection: { filename: './dev.sqlite3' },
useNullAsDefault: true
})
module.exports = knex
`
This gives you the best of both worlds: organized migrations with Knex CLI, and blazing-fast queries in your app!
#### Important: Why Not Use knex-bun-sqlite in knexfile.js?
When you run bun knex migrate:latest or any Knex CLI command, Knex ignores Bun's runtime and invokes Node.js directly to load and execute the migration code. This means:
- â knex-bun-sqlite won't work in your knexfile.js (requires bun:sqlite, which Node.js doesn't have)sqlite3
- â You'll get an error: "Cannot find module 'bun:sqlite'"
- â
Use standard in knexfile.js for CLI commandsknex-bun-sqlite
- â
Use in your application code (via db.js) for the speed benefits
This is why we recommend the two-pronged approach: SQLite3 for migrations, knex-bun-sqlite for queries!
`javascript`
await db.transaction(async (trx) => {
await trx('accounts')
.where('id', 1)
.decrement('balance', 100)
await trx('accounts')
.where('id', 2)
.increment('balance', 100)
})
Benchmark comparison (using Northwind Traders dataset):
| Driver | Read Performance | vs node-sqlite3 |
|--------|------------------|-----------------|
| bun:sqlite | ⥠Fastest | 3-6x faster |
| better-sqlite3 | Fast | 2x faster |
| node-sqlite3 | Baseline | 1x |
| deno sqlite | Slow | 0.5x |
Source: Bun's official benchmarks
This package creates an adapter that:
1. Wraps bun:sqlite's synchronous API
2. Implements the callback-based API that Knex expects
3. Translates between the two APIs seamlessly
4. Preserves all Knex functionality
The adapter implements the complete sqlite3 (node-sqlite3) API that Knex uses:Database
- class with run(), get(), all(), prepare(), etc.Statement
- class for prepared statementslastID
- Proper callback context with and changes propertiesOPEN_READONLY
- Constants like , OPEN_READWRITE, OPEN_CREATE
The adapter provides a sqlite3-compatible Database class:
`typescript
class Database {
constructor(filename: string, mode?: number, callback?: (err: Error | null) => void)
run(sql: string, params?: any[], callback?: (this: RunResult, err: Error | null) => void): void
get(sql: string, params?: any[], callback?: (err: Error | null, row?: any) => void): any
all(sql: string, params?: any[], callback?: (err: Error | null, rows: any[]) => void): any[]
each(sql: string, params?: any[], rowCallback?: (err: Error | null, row: any) => void, completeCallback?: (err: Error | null, count: number) => void): void
exec(sql: string, callback?: (err: Error | null) => void): void
prepare(sql: string, callback?: (err: Error | null) => void): Statement
close(callback?: (err: Error | null) => void): void
serialize(callback?: () => void): void
parallelize(callback?: () => void): void
}
interface RunResult {
lastID: number
changes: number
}
`
- Bun v1.0.0 or higher - This package uses bun:sqlite which is built into Bun
- Knex v2.0.0 or higher - For the query builder
- â ïļ Bun only - This package will not work with Node.js (it requires Bun's native SQLite)
- â ïļ Experimental - While extensively tested, there may be edge cases not covered
This means you're not running in Bun. Make sure to use:
`bash`
bun run your-script.jsnode your-script.js
Not .
Make sure to call await db.destroy() when you're done:`javascript``
async function main() {
// ... your queries
await db.destroy() // Important!
}
Contributions are welcome! Please feel free to submit a Pull Request.
MIT
- Inspired by better-sqlite3
- Built for Bun
- Works with Knex.js
- Bun SQLite Documentation
- Knex.js Documentation
- node-sqlite3