Technote

Development workflow Advanced

Series From local to production Part 8 of 8

Designing rollback: reversing code and database together

Putting the old code back does not put the old data back. If the new code has already migrated your data, the old code cannot read it — hence the order.

This is the last part of the series. You have built a local environment, tidied the repository, separated secrets, moved the database safely, matched staging and added deploys and CI. What remains is how you undo it when something goes wrong.

Start with the most common misconception: putting the old code back does not put the old database back. And in WordPress that is not an edge case — it is the normal behaviour.

Why code-only rollback is not enough

When a plugin or core upgrades, the new code rewrites your data into its own shape at activation or on the first request. It may alter table structures, change the shape of an option array, or move meta keys. That process is generally designed to run in one direction only; no reverse routine is provided.

Put the old code back on top of that and it is now reading data in a shape it does not recognise. If you are lucky, settings appear empty. If you are not, you get a fatal error. That is how rolling back a deploy leaves a site in a worse state than before.

Splitting deploys into two kinds is where rollback design begins

Keep them as a pair, restore them as a pair

Being able to roll back means having a code revision and a database snapshot as one pair. Capture both immediately before the deploy.

# just before deploying — put the revision in the filename so the pair cannot be lost
REV=$(git rev-parse --short HEAD)
wp db export "backups/$(date +%Y%m%d-%H%M)-${REV}.sql" --add-drop-table

The restore has an order to it: code first, database second.

wp maintenance-mode activate
git checkout "${PREV_REV}"             # 1. the code first
wp db import "backups/${SNAPSHOT}"     # 2. then the database that pairs with it
wp cache flush
sudo systemctl reload php8.3-fpm
wp maintenance-mode deactivate

What happens in the reverse order is the point of this part. Import the old database while the new code is still live and the new code sees data that “needs upgrading” and migrates it again on the next request. The data you just restored is converted back on the spot. Hence: code first.

The rollback order — that code comes before the database is the whole diagram

Rollback has a cost — say so plainly

Restoring the database deletes everything that arrived after the snapshot: orders, enquiries, registrations, comments, for exactly that window. This is not a flaw in the procedure, it is what restoring a snapshot means — which is why a judgement is required.

In practice it divides like this. If the deploy touched only code, rollback is instant and lossless, so there is nothing to weigh up. If the deploy touched data, you choose between restoring the database and accepting the loss window, or not rolling back at all and fixing forward. On a site taking transactions continuously, fixing forward is frequently the right answer.

Whichever you pick, the entire point of this part is to decide it in advance, rather than for the first time in the middle of an incident.

A procedure you have never run is not a procedure

Conditions for a reversible state — while the bottom two hold, there is no rollback plan yet

Part five pays off again here. Rehearsing the rollback on staging is the only way to verify it. Record how long it took, and that figure becomes your expected recovery time for the next incident — measured rather than guessed.

Closing the series

One rule ran through all eight parts: separate what you wrote from what the environment made. What belongs in the repository, where secrets live, which direction data flows, and what can be reversed all followed from that single distinction.

WordPress suits this way of working. WP-CLI exposes installation, migration and inspection as commands, and environment types, hooks and mu-plugins let you express per-environment behaviour in code. What was needed was never an exotic tool — only the discipline to hold the distinction.

Standing this pipeline up on an existing site — a Docker-based rebuild, a staging environment, upgrades and performance work — is handled as one job by our optimization program. The exact order we work in, and what we measure before and after, is published on the process page.

More on this topic

All technotes

Development workflow Advanced

Running WP-CLI in CI: what the checks actually look like

Checks that rely on somebody remembering get skipped in a busy week. Stack the cheap ones first, run the rest against a disposable WordPress, and the remembering stops…

Developers 8 min read

₩270,000 · Join the program