An automatic deployment rule is a written answer to one question: under exactly what conditions does code reach users without a person clicking anything? Most teams have rules. Far fewer have written them down, which is why the rules change quietly every time someone is in a hurry.
The failure is not usually a missing pipeline. It is a pipeline whose conditions drifted — a required check that got marked non-blocking during a bad week, a branch that deploys straight to production because it was convenient once, an approval step that everyone approves without reading. Automation amplifies whatever policy you actually have, so the policy is worth being explicit about.
Table of contents
- The four things a rule has to specify
- Branch to environment mapping
- Conditions that are worth blocking on
- Database migrations break the model
- Automatic rollback, and its one hard requirement
- Rules that hold up over time
- How this fits the rest of the stack
- FAQ
The four things a rule has to specify
A deployment rule that is complete answers all four. One that answers three is where the surprises come from.
- Trigger. What starts it — a push to a branch, a merged pull request, a tag, a schedule, a manual dispatch.
- Conditions. What must be true before it proceeds — tests green, review approved, no active incident, inside a deploy window.
- Target. Where it goes — preview, staging, production, one region or all of them.
- Reversal. What happens when it goes wrong — automatic rollback on a health check, manual rollback, roll forward only.
That fourth one is the one people skip, and it is the one that matters at two in the morning. A pipeline that can deploy in ninety seconds and needs twenty minutes of manual work to undo is not fast; it is fast in one direction, which is a different and worse property.
Write the four for each environment. It fits on half a page and it turns a set of habits into something a new engineer can read.
Branch to environment mapping
The most common shape, and the reason it works, is that each rule is boring and predictable.
- Pull request opened or updated — build, run tests, deploy an isolated preview. No approval needed. Nothing user-facing is at risk.
- Merge to main — deploy to staging automatically. Every merged change lands somewhere real within minutes.
- Tag or release — deploy to production. Requires the staging deploy to have succeeded.
Where teams get into trouble is a fourth rule that says and sometimes we push straight to production from a hotfix branch. That path exists at every company. The mistake is leaving it undocumented, so it has no conditions attached and nobody knows it was used until they read the deploy history afterwards.
Make the emergency path explicit instead. Give it a name, require one approval rather than two, log it loudly, and require a follow-up pull request within a day. A documented fast path gets used correctly; an undocumented one gets used badly.
Preview environments per pull request are the highest-value rule on that list and the one most often skipped on cost grounds. They change review from reading a diff to using the change, and they catch a category of problem that no test suite finds.
Conditions that are worth blocking on
Every blocking check trades safety against speed. Some trades are clearly good and some are theatre.
Worth blocking on:
- The build succeeding. Non-negotiable and free.
- Unit and integration tests passing.
- A migration having run successfully against a copy of production data.
- Required review approval on anything touching auth, billing, or data deletion.
Usually not worth blocking on:
- Flaky end-to-end tests. A check that fails 15% of the time for no reason trains everyone to re-run it without reading, which destroys the value of every other check.
- Coverage thresholds to the percentage point. Report them; do not gate on them.
- Lint rules that auto-fix. Fix them in the pipeline instead of failing the build.
The principle underneath: a check that gets routinely bypassed is worse than no check, because it produces the feeling of safety without the substance. If a gate is being skipped every week, either fix the gate or remove it. Leaving it in place while everyone ignores it is the worst of the three options.
Database migrations break the model
Application code can be rolled back. Schema changes usually cannot, and that asymmetry is where most bad automatic deployments live.
The rule that survives contact with reality is expand and contract. Deploy changes in a shape where old and new code can both run against the schema at the same time:
- Add the new column, nullable, with a default. Deploy. Old code ignores it.
- Deploy code that writes to both old and new, and reads from the old.
- Backfill the new column.
- Deploy code that reads from the new column.
- Only once nothing references the old column, drop it — days or weeks later.
Every step is independently reversible. Compare with a single deploy that renames a column: the moment it lands, rolling back the code breaks the application against a schema that no longer matches. There is no undo, only a scramble.
So the deployment rule for migrations is narrower than for code. Additive migrations can run automatically. Destructive ones — dropping columns, dropping tables, changing types in place — get a separate, manual, explicitly-approved path. Encode that distinction in the pipeline rather than in a team norm, because norms do not survive a Friday afternoon.
Automatic rollback, and its one hard requirement
The best automatic rule is the one that undoes a bad deploy without waking anyone. It requires a signal the pipeline can actually read.
- Health check failing after deploy. The cheapest and most reliable. If the new version does not answer a health endpoint within N seconds, roll back.
- Error rate crossing a threshold. Compare the five minutes after the deploy to the hour before. A tenfold jump in 5xx is not ambiguous.
- Latency regression. A p99 that doubles is worth reverting even when nothing is technically erroring.
- A canary cohort failing. Route a small share of traffic to the new version first and compare.
The hard requirement is that the previous version must still be deployable at any moment. That means immutable, versioned artifacts rather than a build that has to be reconstructed from source. If rolling back means re-running a build that pulls whatever dependency versions resolve today, the rollback is a new deploy wearing a rollback costume, and it can fail in its own new way.
Keep enough previous versions to go back more than one step. The bad deploy is not always the most recent one.
Rules that hold up over time
A short list that tends to survive contact with a growing team:
- Deploy small and often. A ten-line deploy that breaks is diagnosable in minutes. A two-week deploy that breaks is an investigation.
- One artifact, promoted between environments. Build once, deploy the same bytes to staging and production. Rebuilding per environment means staging never proved anything about production.
- Every deploy is attributable. Commit, author, timestamp, and log, visible without SSH access.
- Rollback is one action. If it needs a runbook, it needs work.
- Deploy windows are a smell. A rule against deploying on Fridays is a rule that says rollback is not trusted. Fix the rollback.
- Secrets never come from the repository. Environment variables per environment, injected at runtime, rotatable without a rebuild.
Nearly all of that is really one idea seen from different angles: make the reversal cheap, and every other rule can be looser.
How this fits the rest of the stack
The rules are only as good as the platform underneath them, and the part that is easiest to underinvest in is the reversal. On RunxBuild every deploy keeps its build log and its predecessor, so going back to the previous working version is an action rather than a procedure, and the failing build and the failing request are readable in the same place. Environment variables are set per service rather than baked into an image, which is what makes promoting one artifact between environments practical — services on RunxBuild covers deploys, variables, logs, and rollback together. If a per-pull-request preview environment is the rule you have been skipping on cost grounds, the RunxBuild hosting calculator prices the service, database, and bandwidth separately so you can see what a second environment actually adds.
Useful related references:
- Python Dot Product: From Two Lists to NumPy Shape Rules
- Bash Variables: Quoting, Scope, and the Rules That Prevent Disasters
- 443 Port TCP: HTTPS, TLS Handshake, and Firewall Rules
- Services on RunxBuild
FAQ
What are automatic deployment rules?
They are the written conditions under which code reaches an environment without a human action — the trigger, the conditions that must be true, the target environment, and what happens on failure. Most teams have these rules implicitly; writing them down is what stops them drifting.
Should database migrations run automatically?
Additive ones can — adding a nullable column or a new table is reversible in practice. Destructive changes like dropping columns or altering types should require explicit approval, because the application rollback no longer matches the schema. Use expand-and-contract so each step is independently reversible.
What is the difference between continuous delivery and continuous deployment?
Continuous delivery means every change is built, tested, and ready to release, with a human deciding when. Continuous deployment removes that decision — anything passing the gates goes live automatically. The gap between them is entirely about how much you trust your checks and your rollback.
When should a deploy roll back automatically?
The most reliable trigger is a health check failing after the new version starts. Error rate and latency thresholds compared against a pre-deploy baseline also work well. The hard requirement is that the previous artifact is still deployable immediately, without rebuilding from source.
Is it bad to block deploys on end-to-end tests?
It is bad to block on flaky ones. A check that fails randomly trains the team to re-run without reading, which devalues every other gate. Either stabilise the suite, run it in a non-blocking lane, or narrow it to the handful of paths that genuinely must work.