bun:sqlite
module.
bun:sqlite
.
Features include:
- Transactions
- Parameters (named & positional)
- Prepared statements
- Datatype conversions (
BLOB
becomesUint8Array
) - Map query results to classes without an ORM -
query.as(MyClass)
- The fastest performance of any SQLite driver for JavaScript
bigint
support- Multi-query statements (e.g.
SELECT 1; SELECT 2;
) in a single call to database.run(query)
bun:sqlite
module is roughly 3-6x faster than better-sqlite3
and 8-9x faster than deno.land/x/sqlite
for read queries. Each driver was benchmarked against the Northwind Traders dataset. View and run the benchmark source.
Database
To open or create a SQLite3 database:readonly
mode:
Strict mode
By default,bun:sqlite
requires binding parameters to include the $
, :
, or @
prefix, and does not throw an error if a parameter is missing.
To instead throw an error when a parameter is missing and allow binding without a prefix, set strict: true
on the Database
constructor:
Load via ES module import
You can also use an import attribute to load a database..close(throwOnError: boolean = false)
To close a database connection, but allow existing queries to finish, call .close(false)
:
.close(true)
:
close(false)
is called automatically when the database is garbage collected. It is safe to call multiple times but has no effect after the first.
using
statement
You can use the using
statement to ensure that a database connection is closed when the using
block is exited.
.serialize()
bun:sqlite
supports SQLite’s built-in mechanism for serializing and deserializing databases to and from memory.
.serialize()
calls sqlite3_serialize
.
.query()
Use the db.query()
method on your Database
instance to prepare a SQL query. The result is a Statement
instance that will be cached on the Database
instance. The query will not be executed.
Use the
.prepare()
method to prepare a query without caching it on the Database
instance.WAL mode
SQLite supports write-ahead log mode (WAL) which dramatically improves performance, especially in situations with many concurrent readers and a single writer. It’s broadly recommended to enable WAL mode for most typical applications. To enable WAL mode, run this pragma query at the beginning of your application:What is WAL mode
What is WAL mode
In WAL mode, writes to the database are written directly to a separate file called the “WAL file” (write-ahead log). This file will be later integrated into the main database file. Think of it as a buffer for pending writes. Refer to the SQLite docs for a more detailed overview.On macOS, WAL files may be persistent by default. This is not a bug, it is how macOS configured the system version of SQLite.
Statements
AStatement
is a prepared query, which means it’s been parsed and compiled into an efficient binary form. It can be executed multiple times in a performant way.
Create a statement with the .query
method on your Database
instance.
?1
) or named ($param
or :param
or @param
).
Statement
can be executed with several different methods, each returning the results in a different form.
Binding values
To bind values to a statement, pass an object to the.all()
, .get()
, .run()
, or .values()
method.
strict: true
lets you bind values without prefixes
By default, the $
, :
, and @
prefixes are included when binding values to named parameters. To bind without these prefixes, use the strict
option in the Database
constructor.
.all()
Use .all()
to run a query and get back the results as an array of objects.
sqlite3_reset
and repeatedly calls sqlite3_step
until it returns SQLITE_DONE
.
.get()
Use .get()
to run a query and get back the first result as an object.
sqlite3_reset
followed by sqlite3_step
until it no longer returns SQLITE_ROW
. If the query returns no rows, undefined
is returned.
.run()
Use .run()
to run a query and get back undefined
. This is useful for schema-modifying queries (e.g. CREATE TABLE
) or bulk write operations.
sqlite3_reset
and calls sqlite3_step
once. Stepping through all the rows is not necessary when you don’t care about the results.
The lastInsertRowid
property returns the ID of the last row inserted into the database. The changes
property is the number of rows affected by the query.
.as(Class)
- Map query results to a class
Use .as(Class)
to run a query and get back the results as instances of a class. This lets you attach methods & getters/setters to results.
Object.create
than new
. The class’s prototype is assigned to the object, methods are attached, and getters/setters are set up, but the constructor is not called.
The database columns are set as properties on the class instance.
.iterate()
(@@iterator
)
Use .iterate()
to run a query and incrementally return results. This is useful for large result sets that you want to process one row at a time without loading all the results into memory.
@@iterator
protocol:
.values()
Use values()
to run a query and get back all results as an array of arrays.
sqlite3_reset
and repeatedly calls sqlite3_step
until it returns SQLITE_DONE
.
.finalize()
Use .finalize()
to destroy a Statement
and free any resources associated with it. Once finalized, a Statement
cannot be executed again. Typically, the garbage collector will do this for you, but explicit finalization may be useful in performance-sensitive applications.
.toString()
Calling toString()
on a Statement
instance prints the expanded SQL query. This is useful for debugging.
sqlite3_expanded_sql
. The parameters are expanded using the most recently bound values.
Parameters
Queries can contain parameters. These can be numerical (?1
) or named ($param
or :param
or @param
). Bind values to these parameters when executing the query:
Integers
sqlite supports signed 64 bit integers, but JavaScript only supports signed 52 bit integers or arbitrary precision integers withbigint
.
bigint
input is supported everywhere, but by default bun:sqlite
returns integers as number
types. If you need to handle integers larger than 2^53, set safeIntegers
option to true
when creating a Database
instance. This also validates that bigint
passed to bun:sqlite
do not exceed 64 bits.
By default, bun:sqlite
returns integers as number
types. If you need to handle integers larger than 2^53, you can use the bigint
type.
safeIntegers: true
When safeIntegers
is true
, bun:sqlite
will return integers as bigint
types:
safeIntegers
is true
, bun:sqlite
will throw an error if a bigint
value in a bound parameter exceeds 64 bits:
safeIntegers: false
(default)
When safeIntegers
is false
, bun:sqlite
will return integers as number
types and truncate any bits beyond 53:
Transactions
Transactions are a mechanism for executing multiple queries in an atomic way; that is, either all of the queries succeed or none of them do. Create a transaction with thedb.transaction()
method:
db.transaction()
returns a new function (insertCats
) that wraps the function that executes the queries.
To execute the transaction, call this function. All arguments will be passed through to the wrapped function; the return value of the wrapped function will be returned by the transaction function. The wrapped function also has access to the this
context as defined where the transaction is executed.
begin
a transaction when insertCats
is called and commit
it when the wrapped function returns. If an exception is thrown, the transaction will be rolled back. The exception will propagate as usual; it is not caught.
Nested transactions — Transaction functions can be called from inside other transaction functions. When doing so, the inner transaction becomes a savepoint.
View nested transaction example
View nested transaction example
deferred
, immediate
, and exclusive
versions.
.loadExtension()
To load a SQLite extension, call .loadExtension(name)
on your Database
instance
For macOS users
For macOS users
MacOS users By default, macOS ships with Apple’s proprietary build of SQLite, which doesn’t support extensions. To use extensions, you’ll need to install a vanilla build of SQLite.To point
bun:sqlite
to the new build, call Database.setCustomSQLite(path)
before creating any Database
instances. (On other operating systems, this is a no-op.) Pass a path to the SQLite .dylib
file, not the executable. With recent versions of Homebrew this is something like /opt/homebrew/Cellar/sqlite/<version>/libsqlite3.dylib
..fileControl(cmd: number, value: any)
To use the advanced sqlite3_file_control
API, call .fileControl(cmd, value)
on your Database
instance.
value
can be:
number
TypedArray
undefined
ornull
Reference
Datatypes
JavaScript type | SQLite type |
---|---|
string | TEXT |
number | INTEGER or DECIMAL |
boolean | INTEGER (1 or 0) |
Uint8Array | BLOB |
Buffer | BLOB |
bigint | INTEGER |
null | NULL |