VACUUM INTO: The SQLite Backup Command Most People Skip
Most SQLite backup advice still says "stop the service and copy the file." VACUUM INTO (SQLite 3.27+) gives you something better: a consistent, compacted backup that you can take while the service is running.
VACUUM INTO 'backup-2026-08-26.db';
It writes a brand-new database file containing the current data, with free pages reclaimed. No -wal juggling, no lock dance, no "oops I copied before the checkpoint."
Why I trust it over a file copy
- Consistent by construction. It reads through SQLite's own engine, so you never get a torn copy. In WAL mode this matters even more — a plain
cpofapp.dbcan miss the latest writes sitting in-wal. - Safe while running. SQLite handles the concurrent access internally. I run it on a schedule with zero downtime.
- Compacts the file. The output is defragmented — often noticeably smaller than the source.
When it is not the answer
VACUUM INTO reads the database, so it fails on databases whose structure is broken. In my own corruption testing, this was the pattern:
- Bit-rot inside row content (garbled bytes in a value):
VACUUM INTOsucceeds — the copy is structurally valid, though the corrupted content rides along. - Truncated file / zeroed page (structure gone):
VACUUM INTOfails withdatabase disk image is malformed (11).
So use it as your regular backup, not your disaster recovery. For a broken file, the fallback is a real backup or the CLI's .recover.
My routine
- Daily:
VACUUM INTOto a timestamped file (running, zero downtime). - Weekly: restore one backup into a scratch DB and run
PRAGMA integrity_check— prove the backups actually work. - Before any risky migration: a fresh
VACUUM INTO.
If you are about to build a SQLite-backed service, estimate the on-disk size first with the calculator below — then set up this backup routine before you have data you cannot afford to lose.
Comments (0)
No comments yet.