bun:sqlite module — no installation required.
bun:sqlite is roughly 3–6x faster than better-sqlite3 for read queries.
Features:
- Prepared statements (cached and uncached)
- Named and positional parameters
- Transactions with savepoints
BLOB→Uint8Arraytype conversion- Map rows to class instances with
.as(Class) bigintsupport for 64-bit integers- WAL mode for better write concurrency
- Multi-statement queries via
db.run()
Opening a database
Import attribute
Load a database directly via an import statement:Strict mode
By default, named parameters require a$, :, or @ prefix. With strict: true, you can bind values without prefixes, and missing parameters throw an error:
Closing a database
close(false) is called automatically when the database is garbage collected.
Using the using statement
Queries and statements
db.query() — cached prepared statements
db.query() compiles and caches the SQL statement. Calling it again with the same SQL string returns the cached compiled form, not a new compilation.
Caching applies to the compiled prepared statement, not the query results. The same cached statement can be reused safely with different parameter values.
db.prepare() — uncached prepared statements
Use db.prepare() when you want a fresh Statement that is not stored in the cache (e.g., for dynamically generated SQL):
db.run() — execute without reading results
Use db.run() for INSERT, UPDATE, DELETE, or DDL statements where you don’t need rows back:
{ lastInsertRowid: number, changes: number }.
Statement methods
AStatement is a compiled query that can be executed multiple times with different parameter values.
Binding parameters
Named parameters use$, :, or @ prefixes (or no prefix when strict: true):
? or ?N:
.get() — fetch first row
.all() — fetch all rows
.run() — execute and get metadata
.values() — fetch rows as arrays
.iterate() — stream rows one at a time
Useful for large result sets that shouldn’t be fully loaded into memory:
.as(Class) — map rows to class instances
The class constructor is not called. Columns are assigned directly to the object and the class prototype is attached. Use this for methods and getters, not constructor initialization.
.toString() — inspect expanded SQL
.finalize() — free resources
Transactions
Wrap multiple queries in an atomic transaction usingdb.transaction():
Transaction modes
Nested transactions (savepoints)
Calling one transaction function from inside another creates a savepoint:WAL mode
Write-ahead log mode significantly improves write performance and allows concurrent readers. Enable it at startup:WAL sidecar file cleanup
WAL mode creates-wal and -shm sidecar files. On macOS (which uses Apple’s SQLite), these persist after db.close(). To clean them up reliably on all platforms:
Integer handling
SQLite supports 64-bit signed integers, but JavaScript numbers only safely represent up to 53 bits. By default,bun:sqlite returns integers as number. Enable safeIntegers to use bigint for large values:
safeIntegers: true, passing a bigint that exceeds 64 bits throws a RangeError.
Serialization
Serialize and deserialize the entire database to/from aUint8Array:
Loading extensions
On macOS, Apple’s system SQLite does not support extensions. Install a vanilla SQLite via Homebrew and point
bun:sqlite to it: