Skip to main content
For a file-backed SQLite store use native maintenance to capture committed WAL contents. Do not copy a live database with cp or open it through a separately bundled SQLite library inside the engine process. PostgreSQL needs its own database/secret recovery procedure.

Take a consistent backup

The Node maintenance API is commerce.maintenance.backupTo(path) (alias backup). It uses SQLite VACUUM INTO and writes an adjacent manifest with checksum, schema/migration metadata, engine version and size. Check maintenance.isSupported() first and retain both files.
Use immutable operator-owned storage. A file and checksum are not a tested recovery plan.

Restore into a new path

The native layer verifies staged bytes, integrity, actual schema and manifest before publication. Existing files, including empty placeholders, require explicit native overwrite; symlinks and WAL/SHM/journal entries are refused. Never overwrite a database still open by any process, or delete active journals to force recovery. DatabaseManager from @stateset/cli provides asynchronous backup() and restore(). Await both. Manager restore requires a new path, always checks checksum/schema, and publishes through a hard link that cannot replace another file. Its filesystem must support hard links. It does not stop external writers or switch traffic for you.

Verify and cut over

  1. Stop writers and preserve the original database plus sidecars for investigation.
  2. Restore to a new controlled path with checksum verification and newer-schema rejection.
  3. Open a new engine; require integrity check ok and verify schema/migration metadata.
  4. Check representative orders, stock, payments/returns, pending work, events and receipt tail.
  5. Test read-only access, then one writer, before progressively switching traffic.
Built-in migrations are forward-only. Reversing an engine upgrade means restoring a verified compatible pre-upgrade snapshot; application migrations with explicit down SQL are a separate registry. A rollback after new writes can discard business state.

Choose durability explicitly

SQLite uses WAL and defaults to synchronous=NORMAL. Set STATESET_SQLITE_SYNCHRONOUS=FULL before opening the engine for commit-time synchronization across pooled connections. Invalid settings, including OFF, fail. FULL still depends on the filesystem/device honoring sync; it is not a host power-loss certification. Shutdown reports blocked WAL checkpoints: close competing readers/writers and retry. Retained source drills cover process termination before commit and after commit/before response, same-key contention, bounded storage exhaustion, restore and receipt reconciliation. Those are scoped tests, not measured production RPO/RTO, sustained soak, or host power-loss evidence.

Export is a different operation

Native maintenance also offers versioned JSON export/import. Coverage is domain-specific; imports remap identities and cannot reconstruct every state-machine history from a create. Use snapshots for identity-preserving disaster recovery. Inspect the installed export/import contract before treating a round trip as a full backup. See HTTP receipt recovery for unresolved requests, and governed replay for durable command receipts.
Last modified on October 20, 2026