DatabaseSync
History
timeout option.path argument now supports Buffer and URL objects.This class represents a single connection to a SQLite database. All APIs exposed by this class execute synchronously.
new DatabaseSync(path, options?): DatabaseSync
':memory:'.Objectbooleantrue, the database is opened by the constructor. When
this value is false, the database must be opened via the open() method.
Default: true.booleantrue, the database is opened in read-only mode.
If the database does not exist, opening it will fail. Default: false.booleantrue, foreign key constraints
are enabled. This is recommended but can be disabled for compatibility with
legacy database schemas. The enforcement of foreign key constraints can be
enabled and disabled after opening the database using
PRAGMA foreign_keys. Default: true.booleantrue, SQLite will accept
double-quoted string literals. This is not recommended but can be
enabled for compatibility with legacy database schemas.
Default: false.booleantrue, the loadExtension SQL function
and the loadExtension() method are enabled.
You can call enableLoadExtension(false) later to disable this feature.
Default: false.number0.booleantrue, integer fields are read as JavaScript BigInt values. If false,
integer fields are read as JavaScript numbers. Default: false.booleantrue, query results are returned as arrays instead of objects.
Default: false.booleantrue, allows binding named parameters without the prefix
character (e.g., foo instead of :foo). Default: true.booleantrue, unknown named parameters are ignored when binding.
If false, an exception is thrown for unknown named parameters. Default: false.booleantrue, enables the defensive flag. When the defensive flag is enabled,
language features that allow ordinary SQL to deliberately corrupt the database file are disabled.
The defensive flag can also be set using enableDefensive().
Default: true.ObjectnumbernumbernumbernumbernumbernumbernumbernumbernumbernumbernumberConstructs a new DatabaseSync instance.
database.aggregate(name, options): void
Registers a new aggregate function with the SQLite database. This method is a wrapper around
sqlite3_create_window_function().
stringObjectbooleanbooleanbooleantrue, integer arguments to options.step and options.inverse
are converted to BigInts. If false, integer arguments are passed as
JavaScript numbers. Default: false.booleantrue, options.step and options.inverse may be invoked with any number of
arguments (between zero and SQLITE_MAX_FUNCTION_ARG). If false,
inverse and step must be invoked with exactly length arguments.
Default: false.Function is passed the identity will be its return value.FunctionFunctionFunctionaggregate method will work as a window function.
The function receives the current state and the dropped row value. The return value of this function should be the
new state.When used as a window function, the result function will be called multiple times.
const { DatabaseSync } = require('node:sqlite'); const db = new DatabaseSync(':memory:'); db.exec(` CREATE TABLE t3(x, y); INSERT INTO t3 VALUES ('a', 4), ('b', 5), ('c', 3), ('d', 8), ('e', 1); `); db.aggregate('sumint', { start: 0, step: (acc, value) => acc + value, }); using query = db.prepare('SELECT sumint(y) as total FROM t3'); query.get(); // { total: 21 }
import { DatabaseSync } from 'node:sqlite'; const db = new DatabaseSync(':memory:'); db.exec(` CREATE TABLE t3(x, y); INSERT INTO t3 VALUES ('a', 4), ('b', 5), ('c', 3), ('d', 8), ('e', 1); `); db.aggregate('sumint', { start: 0, step: (acc, value) => acc + value, }); using query = db.prepare('SELECT sumint(y) as total FROM t3'); query.get(); // { total: 21 }
database.close(): void
Closes the database connection. An exception is thrown if the database is not
open. An ERR_INVALID_STATE error is thrown if the method is called while
a statement is executing, such as inside a user-defined function, an aggregate
function, an authorizer callback, or a 'sqlite.db.query' subscriber. This
method is a wrapper around sqlite3_close_v2().
database.loadExtension(path, entryPoint?): void
Loads a shared library into the database connection. This method is a wrapper
around sqlite3_load_extension(). It is required to enable the
allowExtension option when constructing the DatabaseSync instance.
import { DatabaseSync } from 'node:sqlite'; const database = new DatabaseSync(':memory:', { allowExtension: true }); // Load using the entry point derived from the filename. database.loadExtension('./decimal.dylib'); // Override the entry point when the derived name does not match. database.loadExtension('./base64.dylib', 'sqlite3_base64_init');
const { DatabaseSync } = require('node:sqlite'); const database = new DatabaseSync(':memory:', { allowExtension: true }); // Load using the entry point derived from the filename. database.loadExtension('./decimal.dylib'); // Override the entry point when the derived name does not match. database.loadExtension('./base64.dylib', 'sqlite3_base64_init');
database.enableLoadExtension(allow): void
booleanEnables or disables the loadExtension SQL function, and the loadExtension()
method. When allowExtension is false when constructing, you cannot enable
loading extensions for security reasons.
database.enableDefensive(active): void
booleanEnables or disables the defensive flag. When the defensive flag is active,
language features that allow ordinary SQL to deliberately corrupt the database file are disabled.
See SQLITE_DBCONFIG_DEFENSIVE in the SQLite documentation for details.
database.location(dbName?): string | null
string'main' (the default primary database) or any other
database that has been added with ATTACH DATABASE Default: 'main'.This method is a wrapper around sqlite3_db_filename()
database.exec(sql): void
stringThis method allows one or more SQL statements to be executed without returning
any results. This method is useful when executing SQL statements read from a
file. This method is a wrapper around sqlite3_exec().
database.function(name, options?, fn): void
stringObjectbooleanbooleanbooleantrue, integer arguments to function
are converted to BigInts. If false, integer arguments are passed as
JavaScript numbers. Default: false.booleantrue, function may be invoked with any number of
arguments (between zero and SQLITE_MAX_FUNCTION_ARG). If false,
function must be invoked with exactly function.length arguments.
Default: false.FunctionNULL if the return value is undefined.This method is used to create SQLite user-defined functions. This method is a
wrapper around sqlite3_create_function_v2().
database.setAuthorizer
History
database.setAuthorizer(callback): void
Sets an authorizer callback that SQLite will invoke whenever it attempts to
access data or modify the database schema through prepared statements.
This can be used to implement security policies, audit access, or restrict certain operations.
This method is a wrapper around sqlite3_set_authorizer().
When invoked, the callback receives five arguments:
numberSQLITE_INSERT, SQLITE_UPDATE, SQLITE_SELECT).The callback must return one of the following constants:
SQLITE_OK- Allow the operation.SQLITE_DENY- Deny the operation (causes an error).SQLITE_IGNORE- Ignore the operation (silently skip).
SQLite requires that the authorizer callback not modify the database connection
that invoked it, which includes preparing and stepping statements. Methods that
would do so throw an error with code ERR_INVALID_STATE while the callback is
on the stack, including database.prepare(), database.exec(), the execution
methods of that connection's statements, iterators, and tag stores, and
database.setAuthorizer() itself. Other connections remain usable.
The callback can also be invoked from within statement.run(),
statement.get(), and similar methods, because SQLite may re-prepare a
statement during execution after a schema change.
Separately, a statement that is currently being executed cannot be reentered.
Calling statement.close() on it would free the virtual machine that is
running, and re-running it through statement.run(), statement.get(),
statement.all(), statement.iterate(), iterator.next(),
iterator.return(), or the equivalent tag store methods would reset that
virtual machine mid-execution. All of these throw an ERR_INVALID_STATE error
instead. This applies to any callback SQLite invokes during execution, such as a
user-defined function. Other statements on the connection remain usable.
Operations that touch no SQLite state stay available from the callback:
sqlTagStore.clear(), which only drops cached statements, and next() and
return() on an already-drained iterator, which keep returning
{ done: true }.
const { DatabaseSync, constants } = require('node:sqlite'); const db = new DatabaseSync(':memory:'); // Set up an authorizer that denies all table creation db.setAuthorizer((actionCode) => { if (actionCode === constants.SQLITE_CREATE_TABLE) { return constants.SQLITE_DENY; } return constants.SQLITE_OK; }); // This will work using query = db.prepare('SELECT 1'); query.get(); // This will throw an error due to authorization denial try { db.exec('CREATE TABLE blocked (id INTEGER)'); } catch (err) { console.log('Operation blocked:', err.message); }
import { DatabaseSync, constants } from 'node:sqlite'; const db = new DatabaseSync(':memory:'); // Set up an authorizer that denies all table creation db.setAuthorizer((actionCode) => { if (actionCode === constants.SQLITE_CREATE_TABLE) { return constants.SQLITE_DENY; } return constants.SQLITE_OK; }); // This will work using query = db.prepare('SELECT 1'); query.get(); // This will throw an error due to authorization denial try { db.exec('CREATE TABLE blocked (id INTEGER)'); } catch (err) { console.log('Operation blocked:', err.message); }
booleanbooleansqlite3_get_autocommit().ObjectAn object for getting and setting SQLite database limits at runtime. Each property corresponds to an SQLite limit and can be read or written.
const db = new DatabaseSync(':memory:'); // Read current limit console.log(db.limits.length); // Set a new limit db.limits.sqlLength = 100000; // Reset a limit to its compile-time maximum db.limits.sqlLength = Infinity;
Available properties: length, sqlLength, column, exprDepth,
compoundSelect, vdbeOp, functionArg, attach, likePatternLength,
variableNumber, triggerDepth.
Setting a property to Infinity resets the limit to its compile-time maximum value.
database.open(): void
Opens the database specified in the path argument of the DatabaseSync
constructor. This method should only be used when the database is not opened via
the constructor. An exception is thrown if the database is already open.
database.serialize(dbName?): Uint8Array
string'main'
(the default primary database) or any other database that has been added with
ATTACH DATABASE. Default: 'main'.Uint8ArraySerializes the database into a binary representation, returned as a
Uint8Array. This is useful for saving, cloning, or transferring an in-memory
database. This method is a wrapper around sqlite3_serialize().
import { DatabaseSync } from 'node:sqlite'; const db = new DatabaseSync(':memory:'); db.exec('CREATE TABLE t(key INTEGER PRIMARY KEY, value TEXT)'); db.exec("INSERT INTO t VALUES (1, 'hello')"); const buffer = db.serialize(); console.log(buffer.length); // Prints the byte length of the database
const { DatabaseSync } = require('node:sqlite'); const db = new DatabaseSync(':memory:'); db.exec('CREATE TABLE t(key INTEGER PRIMARY KEY, value TEXT)'); db.exec("INSERT INTO t VALUES (1, 'hello')"); const buffer = db.serialize(); console.log(buffer.length); // Prints the byte length of the database
database.deserialize(buffer, options?): void
Uint8Arraydatabase.serialize().Loads a serialized database into this connection, replacing the current
database. The deserialized database is writable. Existing prepared statements
are finalized before deserialization is attempted, even if the operation
subsequently fails. An ERR_INVALID_STATE error is thrown if the method is
called while a database callback is on the stack, for example a user-defined
function, an aggregate function, an authorizer, or a changeset filter or conflict
handler. This method is a wrapper around sqlite3_deserialize().
import { DatabaseSync } from 'node:sqlite'; const original = new DatabaseSync(':memory:'); original.exec('CREATE TABLE t(key INTEGER PRIMARY KEY, value TEXT)'); original.exec("INSERT INTO t VALUES (1, 'hello')"); const buffer = original.serialize(); original.close(); const clone = new DatabaseSync(':memory:'); clone.deserialize(buffer); using query = clone.prepare('SELECT value FROM t'); console.log(query.get()); // Prints: { value: 'hello' }
const { DatabaseSync } = require('node:sqlite'); const original = new DatabaseSync(':memory:'); original.exec('CREATE TABLE t(key INTEGER PRIMARY KEY, value TEXT)'); original.exec("INSERT INTO t VALUES (1, 'hello')"); const buffer = original.serialize(); original.close(); const clone = new DatabaseSync(':memory:'); clone.deserialize(buffer); using query = clone.prepare('SELECT value FROM t'); console.log(query.get()); // Prints: { value: 'hello' }
database.prepare(sql, options?): StatementSync
stringObjectbooleantrue, integer fields are read as BigInts.
Default: inherited from database options or false.booleantrue, results are returned as arrays.
Default: inherited from database options or false.booleantrue, allows binding named
parameters without the prefix character. Default: inherited from
database options or true.booleantrue, unknown named parameters
are ignored. Default: inherited from database options or false.booleantrue, hints to SQLite that this statement will
be retained for a long time and likely reused many times. SQLite currently
responds to this hint by avoiding lookaside memory. Corresponds to the
SQLITE_PREPARE_PERSISTENT flag. Default: false.StatementSyncCompiles a SQL statement into a prepared statement. This method is a wrapper
around sqlite3_prepare_v3().
database.createTagStore(maxSize?): SQLTagStore
integer1000.SQLTagStoreCreates a new SQLTagStore, which is a Least Recently Used (LRU) cache
for storing prepared statements. This allows for the efficient reuse of
prepared statements by tagging them with a unique identifier.
When a tagged SQL literal is executed, the SQLTagStore checks if a prepared
statement for the corresponding SQL query string already exists in the cache.
If it does, the cached statement is used. If not, a new prepared statement is
created, executed, and then stored in the cache for future use. This mechanism
helps to avoid the overhead of repeatedly parsing and preparing the same SQL
statements.
Tagged statements bind the placeholder values from the template literal as parameters to the underlying prepared statement. For example:
sqlTagStore.get`SELECT ${value}`;
is equivalent to:
using statement = db.prepare('SELECT ?'); statement.get(value);
However, in the first example, the tag store will cache the underlying prepared statement for future use.
Note: The
${value}syntax in tagged statements binds a parameter to the prepared statement. This differs from its behavior in untagged template literals, where it performs string interpolation.// This a safe example of binding a parameter to a tagged statement. sqlTagStore.run`INSERT INTO t1 (id) VALUES (${id})`; // This is an *unsafe* example of an untagged template string. // `id` is interpolated into the query text as a string. // This can lead to SQL injection and data corruption. db.run(`INSERT INTO t1 (id) VALUES (${id})`);
The tag store will match a statement from the cache if the query strings (including the positions of any bound placeholders) are identical.
// The following statements will match in the cache: sqlTagStore.get`SELECT * FROM t1 WHERE id = ${id} AND active = 1`; sqlTagStore.get`SELECT * FROM t1 WHERE id = ${12345} AND active = 1`; // The following statements will not match, as the query strings // and bound placeholders differ: sqlTagStore.get`SELECT * FROM t1 WHERE id = ${id} AND active = 1`; sqlTagStore.get`SELECT * FROM t1 WHERE id = 12345 AND active = 1`; // The following statements will not match, as matches are case-sensitive: sqlTagStore.get`SELECT * FROM t1 WHERE id = ${id} AND active = 1`; sqlTagStore.get`select * from t1 where id = ${id} and active = 1`;
The only way of binding parameters in tagged statements is with the ${value}
syntax. Do not add parameter binding placeholders (? etc.) to the SQL query
string itself.
import { DatabaseSync } from 'node:sqlite'; const db = new DatabaseSync(':memory:'); const sql = db.createTagStore(); db.exec('CREATE TABLE users (id INT, name TEXT)'); // Using the 'run' method to insert data. // The tagged literal is used to identify the prepared statement. sql.run`INSERT INTO users VALUES (1, 'Alice')`; sql.run`INSERT INTO users VALUES (2, 'Bob')`; // Using the 'get' method to retrieve a single row. const name = 'Alice'; const user = sql.get`SELECT * FROM users WHERE name = ${name}`; console.log(user); // { id: 1, name: 'Alice' } // Using the 'all' method to retrieve all rows. const allUsers = sql.all`SELECT * FROM users ORDER BY id`; console.log(allUsers); // [ // { id: 1, name: 'Alice' }, // { id: 2, name: 'Bob' } // ]
const { DatabaseSync } = require('node:sqlite'); const db = new DatabaseSync(':memory:'); const sql = db.createTagStore(); db.exec('CREATE TABLE users (id INT, name TEXT)'); // Using the 'run' method to insert data. // The tagged literal is used to identify the prepared statement. sql.run`INSERT INTO users VALUES (1, 'Alice')`; sql.run`INSERT INTO users VALUES (2, 'Bob')`; // Using the 'get' method to retrieve a single row. const name = 'Alice'; const user = sql.get`SELECT * FROM users WHERE name = ${name}`; console.log(user); // { id: 1, name: 'Alice' } // Using the 'all' method to retrieve all rows. const allUsers = sql.all`SELECT * FROM users ORDER BY id`; console.log(allUsers); // [ // { id: 1, name: 'Alice' }, // { id: 2, name: 'Bob' } // ]
database.createSession(options?): Session
ObjectstringstringATTACH DATABASE. Default: 'main'.SessionCreates and attaches a session to the database. This method is a wrapper around sqlite3session_create() and sqlite3session_attach().
database.applyChangeset(changeset, options?): boolean
Uint8ArrayObjectFunctionfilter callback is invoked with the
table name as the first argument. If the return value is falsy, then no
attempt is made to apply any changes to the table.
Otherwise, if the return value is truthy or no filter callback is provided,
all changes related to the table are attempted.FunctionDELETE or UPDATE change does not contain the expected "before" values.DELETE or UPDATE change does not exist.INSERT change results in a duplicate primary key.UNIQUE, CHECK, or NOT NULL constraint
violation.booleanAn exception is thrown if the database is not
open. This method is a wrapper around sqlite3changeset_apply().
import { DatabaseSync } from 'node:sqlite'; const sourceDb = new DatabaseSync(':memory:'); const targetDb = new DatabaseSync(':memory:'); sourceDb.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)'); targetDb.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)'); const session = sourceDb.createSession(); using insert = sourceDb.prepare('INSERT INTO data (key, value) VALUES (?, ?)'); insert.run(1, 'hello'); insert.run(2, 'world'); const changeset = session.changeset(); targetDb.applyChangeset(changeset); // Now that the changeset has been applied, targetDb contains the same data as sourceDb.
const { DatabaseSync } = require('node:sqlite'); const sourceDb = new DatabaseSync(':memory:'); const targetDb = new DatabaseSync(':memory:'); sourceDb.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)'); targetDb.exec('CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT)'); const session = sourceDb.createSession(); using insert = sourceDb.prepare('INSERT INTO data (key, value) VALUES (?, ?)'); insert.run(1, 'hello'); insert.run(2, 'world'); const changeset = session.changeset(); targetDb.applyChangeset(changeset); // Now that the changeset has been applied, targetDb contains the same data as sourceDb.
database[Symbol.dispose]
History
database[Symbol.dispose](): void
Closes the database connection. If the database connection is already closed then this is a no-op.