recipe-manager/docs/ADR-001-sqlite-library-choi...

2.7 KiB

ADR-001: SQLite Library Choice

Date: 2026-03-23
Status: Accepted
Decision: Use sql.js instead of better-sqlite3


Context

During MVP development (iteration 3), better-sqlite3 failed to build on WSL2 with Node.js v22.22.0:

error: 'class v8::ObjectTemplate' has no member named 'SetAccessor'
gyp ERR! build error

Root cause: better-sqlite3 native bindings are not compatible with Node.js v22's V8 API changes.

Options considered:

  1. Downgrade Node.js to v20 LTS

    • Impacts other workspace projects
    • Not sustainable long-term
  2. Wait for better-sqlite3 update

    • Blocks autonomous development
    • Timeline uncertain
  3. Switch to sql.js (pure JavaScript SQLite)

    • Zero native dependencies
    • Works everywhere (WSL2, Docker, browser)
    • Synchronous API available
    • ⚠️ Slightly slower than native (acceptable for single-household use)
  4. Switch to node-sqlite3 (callback-based)

    • ⚠️ Async API violates ARCHITECTURE.md sync preference
    • ⚠️ May have similar v22 compatibility issues

Decision

Use sql.js (https://github.com/sql-js/sql.js) for MVP and beyond.

Rationale:

  • Enables autonomous overnight agent work (no environment blockers)
  • Synchronous API matches original architecture vision
  • Pure JavaScript = portable across all environments
  • Performance difference negligible for ~1000 recipes
  • Can persist to filesystem same as better-sqlite3

Implementation Notes

Package: sql.js (npm install sql.js)

Usage pattern:

import initSqlJs from 'sql.js';

const SQL = await initSqlJs();
const db = new SQL.Database();
// ... same SQL queries as before

Persistence:

// Save to file
const data = db.export();
fs.writeFileSync('data/recipes.db', Buffer.from(data));

// Load from file
const buffer = fs.readFileSync('data/recipes.db');
db = new SQL.Database(buffer);

Migration path:

  • If future performance issues arise, can revisit when better-sqlite3 supports Node v22+
  • Database file format is standard SQLite (portable)

Consequences

Positive:

  • Unblocked autonomous development
  • Zero native build dependencies
  • Easier Docker deployment
  • Works in browser (future PWA feature)

Negative:

  • ⚠️ ~10-20% slower than native bindings (negligible for our use case)
  • ⚠️ Requires explicit save() calls (better-sqlite3 auto-persists)

Neutral:

  • Same SQL syntax and database schema
  • Same overall architecture (just the driver changes)

Status

Accepted — 2026-03-23

Documented environment blocker, evaluated alternatives, chose pragmatic path forward per agent-harness methodology (keep moving vs block on environment).