Blue green vs rolling deployment: how to choose a release strategy
Blue green deployment runs two complete production environments and flips all traffic from the old one to the new one in a single cutover, so rollback is just flipping back. A rolling deployment upgrades instances in place, a batch at a time, so old and new code serve live traffic together until the last instance is replaced. Choose blue green when you want the fastest, cleanest rollback and can afford to run double capacity during the cutover; choose rolling when you have a large fleet, want to avoid paying for a second environment, and your app and database schema can tolerate two versions running at once. On a single server, skip both: an atomic symlink release with health checks gives you most of the benefit of blue green for none of the cost.
Skip the manual setup. DeployManage provisions your server and ships zero-downtime deploys on any cloud.
$ get started freeBlue green deployment keeps two complete production environments, blue (live) and green (the new version), deploys to the idle one, verifies it, then switches the load balancer so every request lands on the new version at once. A rolling deployment has no second environment: it replaces instances in place, a batch at a time, so old and new code both serve real traffic until the final instance is swapped. The verdict is simple. Pick blue green when you want a rollback that takes seconds and you can afford to run double capacity during the cutover. Pick rolling when you run a large fleet, do not want to pay for a duplicate environment, and your code and schema can tolerate two versions running at the same time. If you run one VPS, neither is worth the machinery, and an atomic symlink release (the model behind a good server management panel) gets you most of the benefit of blue green on a single box.
Deployment strategies compared
| Strategy | How traffic shifts | Rollback speed | Extra infrastructure | Risk | Best for |
| Blue green | All at once. The router or load balancer repoints from the blue environment to the green one after health checks pass. | Seconds. Point traffic back at the old environment, which is still running. | High. A full second environment, so roughly 2x capacity during the cutover. | Blast radius is all or nothing: if the new build is bad, 100 percent of users hit it until you flip back. | Teams that want a clean, auditable cutover and instant rollback, and can pay for the spare capacity. |
| Rolling | Gradually. Each batch of instances is drained, replaced, health checked, and returned to the pool. | Slow. Rolling back means running the whole process again in reverse, one batch at a time. | Low. One extra instance or a little surge capacity, not a second environment. | Mixed versions serve traffic for the length of the deploy, so both versions must work against one schema. | Large fleets and Kubernetes, where cost matters and the app is designed for version overlap. |
| Canary | A small, weighted slice (often 1 to 5 percent) goes to the new version, then ramps up if metrics stay clean. | Fast for the canary, since you shift the weight back to zero, but a full promotion still needs a real rollback path. | Medium. A separate pool or weighted routing, plus metrics and automated analysis. | Lowest blast radius, but the highest operational complexity and the need for trustworthy metrics. | High traffic products where a bad release is expensive and you have the observability to detect it fast. |
| Atomic symlink release | Instantly, on one server. The new release directory is built alongside the old one, then a symlink is swapped and the process manager reloads. | Seconds. Re-point the symlink at the previous release and reload. | None beyond disk space for the last few releases. | Small: the risk is a bad build, not a partial cutover. There is no version overlap in the web tier. | Single VPS and small fleets running Laravel, Rails, Django, Node, and similar apps. |
There is a fifth option worth naming so you can rule it out: recreate. Stop the old version, start the new one. It is the default in a lot of naive Docker and systemd setups, it is the only strategy on this list with guaranteed downtime, and the only good reason to use it is a change so incompatible that you cannot let two versions coexist for even a second.
What is the difference between blue green and rolling deployment?
Blue green runs the new version on a second, full copy of production and flips all traffic to it at once, while a rolling deployment upgrades instances in place, batch by batch, inside the existing environment, which means old and new code serve live requests side by side until the last batch is replaced. Everything else follows from that. Blue green buys you an instant rollback because the old environment is still sitting there, warm, with the previous build loaded. Rolling buys you cheaper infrastructure because you never pay for a duplicate fleet. Blue green concentrates risk into one moment; rolling spreads it across the whole deploy window. And rolling imposes a hard constraint that catches teams out: for the length of the deploy, two versions of your application are talking to one database, so version N and version N+1 must both work against the same schema.
What is blue green deployment?
Blue green deployment is a release strategy where you keep two identical production environments, deploy the new build to the idle one, run health checks and smoke tests against it while it takes no live traffic, then switch the router or load balancer to send every request to it, keeping the old environment running as an instant rollback target. The cutover itself is a routing change: swap target groups on an AWS ALB, change the upstream in Nginx or HAProxy and reload, or repoint a Kubernetes Service selector from one ReplicaSet to another. Because the flip is atomic from the user's perspective, in-flight requests finish on the old environment and new requests start on the new one. Two practical notes. First, you pay for double capacity for as long as both environments are up, which is why most teams tear down blue within minutes or hours of a successful cutover rather than keeping it forever. Second, blue green is not a testing strategy. Traffic in staging behaves nothing like traffic in production, and a green environment that passed a smoke test can still fall over at real load.
What is a rolling deployment?
A rolling deployment replaces the running instances of your app in batches: the orchestrator drains connections from a small slice of the fleet, stops those instances, starts the new version there, waits for readiness checks to pass, and only then moves to the next slice, so total capacity stays roughly constant and no second environment is required. This is the default in Kubernetes (a Deployment with maxSurge and maxUnavailable), in AWS ECS, and in most autoscaling group update policies. It is efficient and it is boring in the good sense, which is why it dominates at scale. The costs are real though. A rollback is another rolling operation, so it takes as long as the deploy did, and if you are ten minutes into a twenty node roll when the errors start, you now have a half-deployed fleet to reason about. Rolling also makes your version-overlap window a design requirement rather than an accident: caches, queue payloads, and API responses all have to survive being written by one version and read by the other.
Is canary deployment better than blue green?
Not better, different: a canary routes a small, controlled percentage of real production traffic to the new version, watches error rates, latency, and business metrics, then ramps up or aborts, which catches problems that a blue green cutover would expose to every user at the same moment. Canary is the right answer when a bad release is genuinely expensive and you have the observability to notice within minutes. It is the wrong answer when you do not, because a canary without automated metric analysis is just a slower deploy with extra moving parts. Canary and blue green are also not mutually exclusive. A common production pattern is to stand up the green environment, send it 5 percent of traffic through weighted routing, hold, then shift the remaining 95 percent once the numbers look clean. That combination gives you canary's small blast radius and blue green's one-step rollback.
Recreate and atomic symlink releases
An atomic symlink release is what Capistrano popularized and what most PHP, Ruby, and Python deploy tooling still does. You clone the new code into a fresh timestamped directory, install dependencies, build assets, run migrations, warm caches, and only then swap a current symlink to point at the new release and reload the process manager (PHP-FPM, Puma, Gunicorn) with a graceful reload so in-flight requests finish on the old workers. The swap is a single filesystem operation, so there is no window where a request can see a half-copied release. Rollback is the same operation in reverse: point current at the previous release directory and reload. On one server this is functionally a miniature blue green: you build the new version in isolation, verify it, cut over atomically, and keep the old one on disk to flip back to. It just costs you a few hundred megabytes of disk instead of a second fleet. See zero downtime deployment explained for how the graceful reload actually works, and Laravel deployment for the framework-specific steps (config cache, route cache, queue restart) that have to happen in the right order.
Database migrations are the hard part
Every strategy on this page is easy until you change the schema. The moment version N and version N+1 both hold connections to one database, a migration that is not backward compatible turns a zero downtime deploy into an outage. This is unavoidable in a rolling deploy by definition. It also bites blue green, because green and blue usually share a database (running two databases means dealing with replication and split-brain writes, which is far worse than the problem you were solving).
The fix is expand and contract, sometimes called parallel change. Split every breaking schema change into three deploys. Expand: add the new column or table, nullable, with no reads against it, and have the app write to both old and new. Migrate: backfill existing rows in batches, then switch reads to the new column once the data is complete. Contract: after the old code is fully gone from production, drop the old column. Renaming a column becomes three releases instead of one, and each individual release is safe under version overlap. The rules that fall out of this are worth taping to the wall: never drop or rename a column in the same deploy that stops using it, never add a NOT NULL column without a default, never add an index on a large table without the concurrent variant, and always make new columns nullable first.
One consequence teams miss: expand and contract protects your application, not everything downstream of it. Analytics jobs, BI dashboards, and ETL pipelines often read your production tables or a replica directly, and a column that changes type or quietly starts holding a different meaning will keep the app green while the numbers go wrong. If you have reporting hanging off your app database, it pays to watch for schema changes silently breaking downstream data pipelines as part of the same release checklist, because those failures surface days later, in a meeting, rather than in your error tracker.
Sessions, caches, and other shared state
Version overlap breaks more than schemas. If sessions live in local files or in-process memory, a blue green cutover logs everyone out and a rolling deploy logs out whoever lands on a fresh instance. Put sessions in Redis, a database, or a signed cookie before you attempt either. Cached objects are the same story: if version N+1 serializes a model with a new field and version N deserializes it, you get an exception on a page that has nothing to do with your change. Version your cache keys per release, or namespace them, so old and new never read each other's payloads. Queue jobs deserve the same care, since a job enqueued by the old code can be picked up by a worker running the new code minutes later. Add fields to job payloads, never remove or rename them until the old producers are gone, and restart workers only after the new release is live.
Health checks and gates
A deployment strategy is only as safe as the check that decides whether it worked. Exposing a route that returns 200 unconditionally is worse than useless, because it makes a broken release look healthy. A real readiness check should verify the things that actually break on deploy: the database is reachable, Redis is reachable, migrations have run, and the app can render a trivial page end to end. Keep liveness and readiness separate. Readiness controls whether traffic is routed to the instance; liveness controls whether it gets restarted. Then gate the cutover on it. In blue green, green does not receive traffic until it passes; in rolling, the next batch does not start until the current one is ready; in canary, promotion is gated on error rate and latency staying inside a threshold, not on someone eyeballing a graph.
Which deployment strategy has zero downtime?
Blue green, rolling, canary, and atomic symlink releases can all achieve zero downtime, because none of them take the old version out of service until the new one is proven to serve requests; only recreate (stop everything, then start the new build) has guaranteed downtime, and any of the other four loses its zero downtime property the moment you ship a migration that is not backward compatible. That last clause is the whole game. Most self-described zero downtime outages are not routing failures, they are a dropped column, a NOT NULL constraint added to a populated table, or a blocking index build on a table with millions of rows. Get the migration discipline right and the strategy you pick matters much less than the internet suggests.
What most teams should actually do
If you are on Kubernetes with a real fleet, use rolling, because it is the default, it is cheap, and you already have readiness probes. Layer a canary on top of the handful of services where a bad release costs you money. If you are on a load-balanced fleet of VMs behind an ALB or HAProxy and you want the cleanest rollback story, blue green is worth the extra capacity, and it is far easier to reason about at 2am than a half-completed roll. If you are one of the many small and mid-size teams running a web app on one to three servers, run an atomic symlink release with a real health check and keep the last five releases on disk. That gives you an instant cutover, a rollback measured in seconds, and no second environment to pay for, which is the substance of blue green without the bill. DeployManage does exactly this on the servers it provisions across Hetzner, DigitalOcean, AWS, Vultr, Linode, OVHcloud, and custom VPS: zero downtime atomic releases, health-checked cutovers, instant rollback, and a fleet-wide audit log of every deploy so you can see who shipped what and when. There is a free plan if you want to try it on one box before moving anything real.
Frequently asked questions
Does blue green deployment cost more?
Yes, during the cutover. You run two full production environments at once, so compute cost roughly doubles for as long as both are up. Most teams keep the old environment alive for minutes or hours after the switch as a rollback target, then tear it down, so the extra spend is a slice of each deploy rather than a permanent doubling of the bill.
How do you handle database migrations in a blue green deployment?
Use expand and contract. Blue and green almost always share one database, so the schema must work for both versions at once. Add new columns as nullable, write to both old and new fields, backfill in batches, switch reads, and only drop the old column in a later deploy once the old code is gone from production. Never drop or rename a column in the same release that stops using it.
Can you do blue green deployment on a single server?
Not literally, since blue green means two environments behind a router. But you can get the same properties with an atomic symlink release: build the new version in a separate directory, health check it, swap a symlink, and gracefully reload the process manager. Cutover is instant, rollback is repointing the symlink at the previous release, and you keep paying for one box.
How long should you keep the old environment running after a blue green cutover?
Long enough to be confident the new version is healthy under real traffic, which usually means one full traffic cycle or at minimum 15 to 60 minutes. Watch error rates, latency, and queue depth. Once those look normal and any background jobs written by the new code have processed cleanly, tear down the old environment and stop paying for it.