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 INTOor the backup API, nevercp,copyFileor 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_checkon the copy, run on a schedule. A backup nobody has opened is not known to be one.