A deployment strategy is the plan for how a new version of your service replaces the old one. Most production incidents start with a change, so the way you ship changes decides how many users a bad version can hurt. A good strategy limits the damage and makes rollback fast. This note compares the four common strategies and covers the safety habits around them.
The four strategies#
Each strategy trades speed and cost against risk. They're listed here from simplest to safest.
- Recreate: stop every old instance, then start the new ones. Simple, but users see downtime between the two steps.
- Rolling: replace instances a few at a time. Old and new versions serve traffic together until the rollout ends.
- Blue-green: run two full environments. "Blue" serves traffic while you deploy to "green". When green is healthy, switch the router to green. Blue stays ready for a fast switch back.
- Canary: send a small share of traffic (for example, 1% or 5%) to the new version. Compare its metrics with the old version. Increase the share in steps if it stays healthy.
Comparison#
Put side by side, the trade-offs show up on four points.
| Strategy | Downtime | Rollback speed | Extra cost | Risk to users |
|---|---|---|---|---|
| Recreate | Yes | Slow (redeploy) | None | High: all users at once |
| Rolling | No | Medium (roll back) | Low | Medium |
| Blue-green | No | Fast (switch back) | High: 2x capacity | Medium: all at switch |
| Canary | No | Fast (move traffic) | Low to medium | Low: small share first |
Recreate is fine for internal tools and batch jobs that can stop for a minute. Rolling is the default in Kubernetes Deployments. Canary gives the smallest blast radius (the share of users a bad change can hurt), but it needs good metrics and traffic routing to work.
Environments#
Every strategy above is about the last hop into production, but a change passes through other places first. An environment is a full copy of your service with its own config and data. Most teams use at least three.
| Environment | Purpose | Data |
|---|---|---|
| Dev | Try changes quickly | Fake or seed data |
| Staging | Final check in a production-like setup | Copy or sample, with personal data removed |
| Prod | Serves real users | Real data |
Promote the same artifact from one environment to the next. Staging is only useful if it matches production closely: same versions, same config shape, similar infrastructure.
Automated rollback on health checks#
The comparison table rated each strategy on rollback speed. Rollback is the default fix for a bad deploy (see the on-call process), so let the pipeline do it instead of waiting for a person to wake up. Here's the usual loop:
- Define health signals before you deploy: error rate, latency, and key business metrics.
- Deploy to a first step (one instance, or a small canary share).
- Watch the signals for a fixed bake time, such as 10 minutes.
- Continue to the next step if the signals stay within limits.
- Roll back automatically if any signal crosses its limit.
Health checks come in two levels. A readiness check tells the load balancer that an instance can take traffic. A deploy-level check compares the new version's metrics with the old version's.
Database migrations#
Automatic rollback works well for code, but data is harder. Code rolls back in seconds, but a schema change often can't. During a rolling or canary deploy, old and new code also run at the same time against one database. So every schema change must work with both versions.
The safe pattern is expand and contract. To rename column name to full_name:
- Expand: add the new column
full_name. Old code ignores it. - Dual write: deploy code that writes to both columns and still reads
name. - Backfill: copy existing values from
nameintofull_name, in small batches. - Switch reads: deploy code that reads
full_name. - Contract: stop writing
name. In a later release, drop the column.
Each step is a separate deploy, and you can roll back each one alone. Avoid changes that break old code in one step, such as renaming or dropping a column that the running version still uses.
Large tables need care. Some schema changes lock the table while they run. Check how your database handles the change before you run it in production.
Deploy vs release#
So far "shipping" has meant one thing, but it covers two separate steps. A deploy puts new code on production servers. A release makes a feature visible to users.
When you separate them, you can deploy code with the new feature turned off. Then you turn it on later, for a few users first, with a feature flag. If the feature has a problem, you turn the flag off and don't need a new deploy.
Key takeaways#
- Recreate is simple but has downtime. Rolling is the common default. Blue-green gives instant rollback at double cost. Canary limits blast radius.
- Promote one artifact through dev, staging and prod.
- Define health signals before you deploy, and let the pipeline roll back automatically.
- Make every schema change backward compatible with expand and contract, one step per deploy.
- Deploy is moving code to servers. Release is turning the feature on for users.