knex-bun-sqlite
v1.4.0
Published
Use Bun's native high-performance SQLite driver (bun:sqlite) with Knex.js - 3-6x faster than node-sqlite3
Maintainers
Readme
knex-bun-sqlite
Use 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!
Why?
- 🚀 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
Installation
bun add knex-bun-sqlite knexNote: This package requires Bun runtime (v1.0.0+). It uses
bun:sqlitewhich is only available in Bun.
Quick Start
Method 1: Reusable Database Module (Recommended ⭐)
Create a reusable database module for your application - this is the best practice:
// db.js
const knex = require('knex')({
client: require('knex-bun-sqlite'), // Clean and simple!
connection: { filename: './mydb.sqlite' },
useNullAsDefault: true
})
module.exports = knexThen in your app:
const db = require('./db')
// Use Knex normally
const movies = await db('movies').where('year', '>', 2000).select('*')
await db.destroy()Method 2: Module Interception (Alternative)
If you prefer, you can also use module interception to replace sqlite3 automatically:
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()Features
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)
Examples
Basic Queries
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: '[email protected]'
})
// UPDATE
await db('users')
.where('id', 1)
.update({ email: '[email protected]' })
// DELETE
await db('users').where('inactive', true).del()
// Always clean up!
await db.destroy()Migrations
For Knex CLI migrations (running bun knex migrate:latest), use SQLite3 in your knexfile since Knex itself will invoke the SQLite driver:
// 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:
knex migrate:latest
knex migrate:rollback
knex seed:runFor 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:
// 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 = knexThis 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-sqlitewon't work in your knexfile.js (requiresbun:sqlite, which Node.js doesn't have) - ❌ You'll get an error: "Cannot find module 'bun:sqlite'"
- ✅ Use standard
sqlite3in knexfile.js for CLI commands - ✅ Use
knex-bun-sqlitein your application code (viadb.js) for the speed benefits
This is why we recommend the two-pronged approach: SQLite3 for migrations, knex-bun-sqlite for queries!
Transactions
await db.transaction(async (trx) => {
await trx('accounts')
.where('id', 1)
.decrement('balance', 100)
await trx('accounts')
.where('id', 2)
.increment('balance', 100)
})Performance
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
How It Works
This package creates an adapter that:
- Wraps
bun:sqlite's synchronous API - Implements the callback-based API that Knex expects
- Translates between the two APIs seamlessly
- Preserves all Knex functionality
The adapter implements the complete sqlite3 (node-sqlite3) API that Knex uses:
Databaseclass withrun(),get(),all(),prepare(), etc.Statementclass for prepared statements- Proper callback context with
lastIDandchangesproperties - Constants like
OPEN_READONLY,OPEN_READWRITE,OPEN_CREATE
API Reference
Database Methods
The adapter provides a sqlite3-compatible Database class:
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
}Requirements
- Bun v1.0.0 or higher - This package uses
bun:sqlitewhich is built into Bun - Knex v2.0.0 or higher - For the query builder
Limitations
- ⚠️ 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
Troubleshooting
"Cannot find module 'bun:sqlite'"
This means you're not running in Bun. Make sure to use:
bun run your-script.jsNot node your-script.js.
Script doesn't exit
Make sure to call await db.destroy() when you're done:
async function main() {
// ... your queries
await db.destroy() // Important!
}Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
Credits
- Inspired by better-sqlite3
- Built for Bun
- Works with Knex.js
