@photostructure/sqlite provides 100% API compatibility with Node.js's built-in SQLite module. This means you can use it as a drop-in replacement without changing any code.
Simply change your import statement:
// Before: Using Node.js built-in SQLite (available in Node.js 22.5.0+)
const { DatabaseSync } = require("node:sqlite");
// After: Using @photostructure/sqlite (works on Node.js 22+ without any flags)
const { DatabaseSync } = require("@photostructure/sqlite");
Or with ES modules:
// Before
import { DatabaseSync } from "node:sqlite";
// After
import { DatabaseSync } from "@photostructure/sqlite";
All your existing code will work exactly the same.
Node.js v26.11.0 renamed DatabaseSync and StatementSync to Database and Statement, and deprecates the old names in documentation only (DEP0210, DEP0211). This package exports both names on every supported Node.js version. The examples on this page use DatabaseSync, because node:sqlite has only that name before v26.11.0.
| Node.js version | node:sqlite status |
|---|---|
| 22.5.0–22.12.x | Requires --experimental-sqlite flag |
| 22.13.0–25.6.x | Works without flag, prints ExperimentalWarning |
| 25.7.0+ | Release Candidate (Stability: 1.2), no warning |
# node:sqlite on Node.js 22.5.0–22.12.x:
node --experimental-sqlite app.js
# node:sqlite on Node.js 22.13.0+ OR @photostructure/sqlite on any version:
node app.js
All classes, methods, and properties are identical:
Database class (also exported as DatabaseSync) with all the same methodsStatement class (also exported as StatementSync) with identical behavior// This code works identically with both libraries
const { DatabaseSync, StatementSync } = require("@photostructure/sqlite");
// OR: const { DatabaseSync, StatementSync } = require('node:sqlite');
const db = new DatabaseSync(":memory:");
// Create tables
db.exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
)
`);
// Prepared statements
const insert = db.prepare("INSERT INTO users (name, email) VALUES (?, ?)");
const result = insert.run("Alice", "alice@example.com");
console.log(result.lastInsertRowid);
// Queries
const users = db.prepare("SELECT * FROM users").all();
console.log(users);
// Custom functions
db.function("uppercase", (str) => str.toUpperCase());
const upper = db.prepare("SELECT uppercase(name) as name FROM users").get();
console.log(upper.name); // ALICE
// Cleanup
db.close();
npm install @photostructure/sqlite'node:sqlite' to '@photostructure/sqlite'@photostructure/sqlite exports 20 additional SQLITE_OPEN_* constants for advanced database opening scenarios. These are available via constants.SQLITE_OPEN_* and are useful for low-level control. These constants are additive and don't affect API compatibility.
Node.js's permission model (--permission flag) provides security restrictions that are enforced at the Node.js runtime level. Since @photostructure/sqlite is a userland package, it cannot integrate with this internal security mechanism.
If you use the permission model and need SQLite extension loading restrictions enforced by it, you must use the built-in node:sqlite module.
Workaround: For extension loading control, you can simply avoid calling loadExtension() or set allowExtension: false (the default) when creating databases.
You might want to stick with the built-in module if:
Choose this package when:
node:sqlite reached Release Candidate status (Stability: 1.2) in Node.js v25.7.0, with no flag required. Migrating back when you're ready is trivial:
// Simply change the import back
import { DatabaseSync } from "node:sqlite";
// All your code continues to work unchanged