Dump the database before applying pending migrations - #10
Merged
Conversation
`prisma migrate deploy` is forward-only, so a bad migration against the production database had no way back. A `template-backup` service now runs `pg_dump -Fc` ahead of `template-migrations`, reusing the chaining the app already relies on: template-db (healthy) -> template-backup -> template-migrations -> template-app It runs the `postgres:17` image rather than the app image, so pg_dump is version-matched to the server by construction and there is no client library to keep in sync — the failure mode that a mismatched client causes is structurally impossible here. BACKUP_MODE is off | best-effort | required (default). `required` needs no scripting to enforce: template-migrations waits on service_completed_successfully, so a non-zero backup stops the chain before any DDL runs. An unrecognised value fails rather than silently downgrading. Dumps are verified with `pg_restore --list` and moved into place only after passing, so a truncated file can never look like a good backup. They land on the template-backups volume, pruned to the newest BACKUP_KEEP (default 10). The publish smoke test now asserts the backup exited 0, reported a completed dump, and that the dump passes `pg_restore --list`. Verified against postgres:17: dump/restore round-trip preserves data and utf8, a failed backup leaves template-migrations created-but-never-started, off/best-effort/required and an invalid value all behave, and pruning holds at BACKUP_KEEP with no temp files left behind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
prisma migrate deployis forward-only, so a bad migration against the production database has no way back — and the deploy applies migrations automatically.A
template-backupservice now runspg_dump -Fcahead oftemplate-migrations, reusing the chaining the app already relies on:Design notes
It uses the
postgres:17image, not the app image.pg_dumpis therefore version-matched to the server by construction, and there's no client library to keep in sync. This matters: the equivalent change onva-partnersinitially shipped a client that silently could not authenticate to the database at all, because the auth plugin wasn't in the package. That failure mode is structurally impossible here.requiredneeds no scripting to enforce.template-migrationsalready waits onservice_completed_successfully, so a non-zero backup stops the chain before any DDL runs. Compose does the gating.BACKUP_MODErequired(default)best-effortoffAn unrecognised value fails rather than silently downgrading to a weaker mode.
Dumps are verified before they count.
pg_restore --listmust pass, and the file is moved into place only after that, so a truncated dump can never look like a good backup. Dumps land on thetemplate-backupsvolume, pruned to the newestBACKUP_KEEP(default 10).Scope
Deliberately simpler than the
va-partnersequivalent, which needed an entrypoint script because it had no separate migration service. No fingerprinting or crash-loop handling here — a one-shot service runs once per deploy, not on every container restart.Verification
Against a real
postgres:17:pg_restoreinto a fresh database returns the rows intact, including UTF-8 and embedded apostrophes.03:56:54.145, migrations started at03:56:54.759.BACKUP_MODE,compose upexits 1 and the migrations container is leftcreatedwithStartedAtnever set — it never executed.offskips;best-effortcontinues past a failed dump;requiredexits 1; an invalid value exits 1.BACKUP_KEEPwith no temp files left behind.pg_restore --listcommand added to CI was run as written.Caveat worth carrying forward
These dumps sit on the same host and disk as
template-db. They protect against a bad migration, not against losing the machine. Called out in the README so projects generated from this template don't mistake it for disaster recovery.🤖 Generated with Claude Code