@photostructure/sqlite
    Preparing search index...

    SQLite library comparison

    This guide compares @photostructure/sqlite with the alternatives to help you choose the right SQLite library for Node.js.

    • Broad Node.js support (v22+) — node:sqlite requires Node.js 22.5.0+
    • Decoupled SQLite version — upgrade SQLite independently of your Node.js version
    • Future-proof code that works with both this package AND node:sqlite
    • Synchronous performance with a clean, official API
    • Hassle-free installs — prebuilds are bundled in the npm package (no postinstall downloads)
    • Node-API stability — one prebuild per platform works across Node.js versions
    • Zero migration path to node:sqlite when you're ready
    • Session/changeset support for replication and synchronization
    • A mature, actively maintained synchronous SQLite library
    • Its established API and especially fast row-heavy SELECTs
    • Bundled Node-API prebuilds and Node.js 22+ support

    sqlite3 (node-sqlite3) is unmaintained and deprecated as of December 2025. New projects should not use it. Existing users should migrate to one of the alternatives above.

    • Already on Node.js 22.5.0+ and don't need support for older versions
    • Working in environments where you control the Node.js version
    • Willing to track a release-candidate API that may still have minor changes

    The official SQLite module included with Node.js 22.5.0+. Promoted to Release Candidate (Stability: 1.2) in Node.js v25.7.0.

    node:sqlite availability by Node.js version:

    Node.js node:sqlite status
    v20 Not available
    v22.5.0–22.12.x Requires --experimental-sqlite flag
    v22.13.0+ Experimental (no flag needed, prints warning)
    v24.0.0–24.14.x Experimental (no flag needed, prints warning)
    v24.15.0+ Release Candidate (Stability: 1.2, no warning)
    v25.0.0–25.6.x Experimental (no flag needed, prints warning)
    v25.7.0+ Release Candidate (Stability: 1.2, no warning)
    v26.0.0+ Release Candidate (Stability: 1.2, no warning)

    Pros:

    • Zero dependencies: built directly into Node.js
    • Official support: maintained by the Node.js core team
    • Clean synchronous API: simple, predictable blocking operations
    • Full SQLite power: FTS5, JSON functions, R*Tree, sessions/changesets, and more

    Cons:

    • Release candidate: API is stable but may still have minor changes before final stable designation
    • Requires Node.js 22.5.0+: won't work on older versions
    • Coupled SQLite version: you get whatever SQLite version shipped with your Node.js release — upgrading SQLite means upgrading Node.js

    Best for: Projects already on Node.js 22.5.0+ that want zero dependencies and are comfortable with a release-candidate API.


    A mature, actively maintained synchronous SQLite library with its own API.

    Pros:

    • Mature API: long-established synchronous database and statement interfaces
    • Feature-rich: user functions, aggregates, virtual tables, extensions
    • Fast bulk reads: leads this benchmark when one call materializes roughly 1,000 rows
    • Hassle-free installs: Node-API prebuilds are bundled in the npm package

    Cons:

    • Different API: not compatible with Node.js built-in SQLite
    • Requires Node.js 22+: current releases no longer support older Node.js versions
    • Community TypeScript types: types are provided separately by @types/better-sqlite3
    • Migration effort: switching from other libraries requires code changes
    • No session support: doesn't expose SQLite's session/changeset functionality

    Best for: Projects that prefer its API or prioritize maximum synchronous bulk-read throughput over node:sqlite API compatibility.


    The original asynchronous SQLite binding for Node.js, unmaintained since December 2025

    Status:

    • Deprecated and unmaintained: no new issues or PRs will be addressed
    • No security updates: vulnerabilities will not be patched
    • Bundled SQLite is outdated: ships with SQLite 3.45.0 (current is 3.51.1+)

    Historical context:

    • Was the most widely used SQLite binding for Node.js (4000+ dependent packages)
    • Provided an async/callback API
    • Supported SQLCipher encryption

    Recommendation: Migrate to @photostructure/sqlite, better-sqlite3, or node:sqlite. See migration guide below.

    Feature @photostructure/sqlite node:sqlite better-sqlite3 sqlite3
    API Compatibility node:sqlite - Custom Custom
    SQLite Version Independent Tied to Node.js release Independent Independent
    Min Node.js Version 22.0.0 22.5.0 22.0.0 10.0.0
    Experimental Flag ✅ Never needed ⚠️ Required on 22.5–22.12; not needed since 22.13 ✅ Not needed ✅ Not needed
    Synchronous API
    Asynchronous API
    TypeScript Types ✅ Built-in ✅ Built-in ✅ Via @types ✅ Via @types
    Custom Functions
    Aggregate Functions
    Window Functions
    Sessions/Changesets
    Backup API ✅ Different API
    Extension Loading
    Worker Threads ⚠️ Limited
    FTS5
    JSON Functions
    R*Tree
    Prebuild Strategy Bundled in npm N/A (built-in) Bundled in npm Downloaded on install
    Node-API ✅ N-API 8 N/A ✅ N-API 10
    Disposable Interface ✅ Native C++ ✅ Native C++

    All three synchronous drivers are fast enough for most applications, but they are not equal on every workload. Durable single-row writes tie because storage sync time dominates, and indexed single-row reads are within roughly 20% of the fastest driver in our benchmark. @photostructure/sqlite is slower when one call materializes roughly 1,000 rows.

    The bulk-read results include both binding work and SQLite configuration. Source inspection shows different materialization strategies: better-sqlite3 13 passes values for stable row shapes through cached JavaScript factories, this package assigns each column to a null-prototype row through Node-API property calls, and node:sqlite can use internal V8 APIs. Those architectural differences do not by themselves establish which one causes the measured gap.

    The published range result also includes a configuration difference: better-sqlite3 defaults SQLite's page cache to 16 MiB, while this package and node:sqlite default to 2 MiB. Pinning all three drivers to 2 MiB reduced better-sqlite3's range result from roughly 1,500 to 658 ops/s on this fixture (this package: 413; node:sqlite: 583). The default-cache result is still a valid out-of-box comparison, but it is not purely binding overhead.

    A later same-harness A/B did not reproduce the earlier row-factory result. A compatible factory improved range throughput by only about 2% and did not improve iteration; the confidence intervals overlapped. The candidate therefore failed its 20% acceptance gate and was reverted. The remaining binding-side gap has not been isolated to one mechanism. See the full benchmark results and methodology.

    Both node:sqlite and @photostructure/sqlite provide SQLTagStore for cached prepared statements via tagged template literals. Node.js implements this in native C++, while we use a TypeScript implementation. Benchmarks show equivalent performance:

    Scenario @photostructure/sqlite node:sqlite Difference
    Single query cache hit 141,000 ops/s 155,000 ops/s -9%
    Multi-pattern workload 65,000 ops/s 50,000 ops/s +31%
    Write operations 720 ops/s 720 ops/s 0%

    The TypeScript implementation performs equivalently because SQLite execution time dominates over cache lookup overhead. V8's Map is highly optimized for string keys, matching or exceeding native LRU performance for typical workloads.

    Run npm run bench:tagstore in the benchmark/ directory to reproduce these results.

    // Just change the import - everything else stays the same!
    // From: import { DatabaseSync } from 'node:sqlite';
    import { DatabaseSync } from "@photostructure/sqlite";

    See our detailed migration guide. Key differences:

    • Constructor syntax slightly different
    • Use enhance() for .transaction() and .pragma() helper methods
    • Different property names (e.g., .name.location())
    • Iterator syntax changes

    Note: sqlite3 is deprecated and unmaintained as of December 2025. Migration is strongly recommended.

    Requires rewriting from async to sync patterns:

    // sqlite3 (async)
    db.get("SELECT * FROM users WHERE id = ?", [id], (err, row) => {
    if (err) handleError(err);
    else processUser(row);
    });

    // @photostructure/sqlite (sync)
    try {
    const row = db.prepare("SELECT * FROM users WHERE id = ?").get(id);
    processUser(row);
    } catch (err) {
    handleError(err);
    }
    • @photostructure/sqlite: Actively maintained, tracks Node.js upstream
    • node:sqlite: Part of Node.js core, follows Node.js release cycle
    • better-sqlite3: Actively maintained, with SQLite updates, correctness fixes, and API work
    • sqlite3: Deprecated and unmaintained since December 2025
    • better-sqlite3: Mature ecosystem around its long-established API
    • node:sqlite: Growing community as adoption increases
    • @photostructure/sqlite: New but benefits from node:sqlite compatibility
    • sqlite3: Large legacy community, but no longer maintained

    Choose based on your specific needs:

    1. Need support for all Node.js v22 releases? → @photostructure/sqlite
    2. Already using better-sqlite3 and happy with it? → No urgent reason to switch
    3. Have async legacy code using sqlite3? → Migrate to @photostructure/sqlite or better-sqlite3 (sqlite3 is deprecated)
    4. Already on Node.js v22.13+, v24+, v25.7+, or v26+ with a preference for zero dependencies?node:sqlite