Skip to content
The Handover

Services

SQLite

What we tell an AI agent working on a project that uses SQLite —2 rules, 1 from cases others reported.

Build a rootnote set for a SQLite projectPlain text

SQLite did not publish a file for agents when we last checked, so this page is the only agent-facing guidance for it we know of. Why that matters.

SQLite: back up through SQLite, never by copying the file

Reported by Scott Spence, "SQLite Corruption with fs.copyFile() in WAL Mode" — scottspence.com/posts/sqlite-corruption-fs-copyfile-issue; SQLite, "How To Corrupt An SQLite Database File — Backup or restore while a transaction is active" — www.sqlite.org/howtocorrupt.html · distilled by Leon Mallett (captivated.online) with Claude Code · reviewed 2026-10-25

Scott Spence’s production SQLite database became corrupt, and when he went to the backups, all seven were corrupt too. They had been made with Node’s fs.copyFile() on the live database file every six hours. In WAL mode, SQLite keeps a database in three files — the database, -wal and -shm — and copying only the first while the others are being written produces a corrupt copy. Every backup had been unusable from the moment it was made. A second flaw meant there was effectively one backup a day, not four: the filename had no hour, so each run overwrote the last. He recovered from a development copy he happened to have.

SQLite’s own documentation lists this as a way to corrupt a database, and names the safe methods: VACUUM INTO, the C-language backup API, or sqlite3_rsync.

  • Back up with VACUUM INTO or the backup API, never cp, copyFile or a plain file sync of a database that is open.
  • Make backup names unique to the run, with the time in the name, so one run cannot overwrite another.
  • Check a backup by opening it: PRAGMA integrity_check on the copy, run on a schedule. A backup nobody has opened is not known to be one.

SQLite: foreign keys are off by default, and there is one writer at a time

General guidance · Leon Mallett (captivated.online) with Claude Code · reviewed 2026-10-19

  • Turn foreign keys on for every connection (PRAGMA foreign_keys = ON). They are off by default, so constraints you declared are silently ignored.
  • Use WAL mode wherever readers and a writer overlap.
  • Set a busy timeout and keep writes short. There is one writer at a time, and contention surfaces as a busy error rather than a wait.

Also applies to every database choice, so it is not repeated here:

  • An instruction is not a control: keep production out of the agent's reach, and check recovery yourself
  • Never run a migration or a write against production that has not run against a copy

All of it is included when you build a set.

SupabasePostgresCloudflare D1Turso