# Blue-Green Deployment: How It Works, With a Real Example

> Blue-green deployment explained: how the switch works, pros and cons, when not to use it, and a real Node.js example with 0 failed requests under traffic.

A **blue-green deployment** runs two copies of your app side by side. One copy (blue) serves every visitor while you deploy and check the new version on the other (green). When green is ready, a router moves all traffic to it in one step. If anything goes wrong, you switch back to blue just as fast.

It is one of the oldest tricks for releasing software without downtime, and it still searches like a hot topic, because most explanations stop at a diagram with two boxes. You are left wondering how the switch works on a real server, what happens to requests in flight, and what to do about the database. If you want the wider picture first, our guide to **[zero-downtime deployment strategies](/what-is-zero-downtime-deployment/)** compares blue-green with rolling, canary and the rest.

This guide explains how blue-green deployment works step by step, its pros and cons, when not to use it, and a real example: a Node.js app on xCloud switching to a new release on a second port under steady traffic.

![How a blue-green deployment works: blue serves traffic, green is deployed and checked, the router switches, blue stays as a rollback](/_landing/blog/blue-green-deployment-image-1.png)

## TL;DR

- **Blue-green deployment** = two copies, one live. Deploy to the idle one, check it, switch all traffic at once.
- **Rollback is a switch back,** which makes it the fastest strategy to undo.
- **Zero downtime needs two more pieces:** a health check before the switch and connection draining after it.
- **The database is shared,** so schema changes must work for both copies. Use expand and contract.
- **It costs a second copy** while both run, and it is a poor fit when you need to test with a small share of users first (that is a canary).
- **Real example:** a Node.js app on xCloud did 3 deploys and a rollback with 0 failed requests out of 2,400. The same app restarting in place had 27 failed requests over 3 deploys.

## A Real Blue-Green Switch: 0 Failed Requests vs 27

Here is what blue-green looks like on one real server, not in a diagram. On 10 November 2026 we deployed a small Express app on an xCloud test server (nginx, Node.js) while it got a steady 8 requests a second over HTTPS.

We ran it twice: once with xCloud's **Release mode** on (blue-green on two ports) and once with it off (the app restarts in place).

| | Release mode on (blue-green) | Release mode off (restart in place) |
|---|---|---|
| Deploys | 3, plus 1 rollback | 3 |
| Requests during the test | 2,400 | 880 |
| Failed requests | **0** | **27** (502 errors) |
| What visitors saw | Nothing; the switch was invisible | About a second of errors on every deploy |

With Release mode on, each deploy started the new release on a second port and the deployment log showed the check before the switch:

```
Node health check passed on 127.0.0.1:3003 (HTTP 200).
```

Only then did nginx send new requests to the new port. The old process finished what it was doing and stopped. That is blue-green deployment, at the size of one app on one server.

## What Is Blue-Green Deployment?

**Blue-green deployment is a release technique that keeps two production environments and switches traffic between them in one step.** Martin Fowler's **[BlueGreenDeployment](https://martinfowler.com/bliki/BlueGreenDeployment.html)** article describes it this way: two production environments, as identical as possible, with one live at any time. You do your final testing in the idle one, then switch the router so all requests go there.

Think of a theater with two stages on a turntable. The audience watches one stage while the crew builds the next scene on the other. When it's ready, the turntable rotates. Nobody sees the hammering.

| | Blue | Green |
|---|---|---|
| Before the deploy | Live, serves every request | Idle, or running the old version |
| During the deploy | Live, untouched | New version installed and checked |
| After the switch | Idle, kept as the rollback | Live |
| Next deploy | Gets the new version | Live, untouched |

The colors have no meaning beyond "the other one". After each release the roles swap.

## How Blue-Green Deployment Works, Step by Step

### Step 1: Deploy to the idle environment

Build and install the new version on green while blue keeps serving. Run your dependency install and asset build here, not on the live copy.

### Step 2: Check that green is healthy

Send green a request before it gets any traffic. A good health check hits a real route, such as `/` or `/health`, and fails on a server error or a timeout. If the check fails, stop. Blue never noticed. (Not sure why a build failed? See **[why Git deploys fail](/why-your-git-deploy-failed-on-xcloud/)**.)

### Step 3: Switch the router

Point your load balancer, reverse proxy or DNS at green. With a proxy such as nginx this is a config change and a graceful reload, so it takes effect at once. DNS is the slow option, because clients cache old records.

### Step 4: Drain and keep blue

Let blue finish the requests it already accepted (connection draining), then stop sending it work. Keep it around: blue is your rollback until the next deploy.

### Step 5: Roll back if needed

Something wrong after the switch? Point the router back at blue. The rollback takes as long as the switch, which is the whole appeal.

## Blue-Green on One Server

You don't need two data centers. On a single server, "two environments" can be two processes on two ports, behind the reverse proxy you already run. Here is the general shape with nginx, for a Node.js app:

```nginx
upstream app {
    server 127.0.0.1:3003;   # green (new)
    # server 127.0.0.1:3002; # blue (previous)
}

server {
    listen 80;
    location / {
        proxy_pass http://app;
    }
}
```

The deploy starts the new release on the idle port, checks it with a request, changes the `upstream` port, runs `nginx -t` and a graceful reload, then lets the old process finish and stop. That last step matters: kill the old process too early and long requests are cut off.

For PHP and WordPress there is an even simpler version: build each release in its own folder and switch a link, called release folders or symlink switching. It is blue-green with folders instead of servers.

## Blue-Green Deployment Pros and Cons

| ✅ Pros | ❌ Cons |
|---|---|
| ✅ Instant switch: no moment where some files are old and some are new | ❌ Needs a second copy of the app while both run |
| ✅ Instant rollback: switch back to the copy you kept | ❌ The database is shared, so schema changes need care |
| ✅ The new version is checked before it gets traffic | ❌ All users get the new version at once, so a subtle bug reaches everyone |
| ✅ Easy to reason about: one live copy at a time | ❌ Long-running jobs and sessions need draining and shared storage |
| ✅ Works on one server or many | ❌ DNS-based switching is slow because of caching |

## Blue-Green vs Rolling vs Canary

| | Blue-green | Rolling | Canary |
|---|---|---|---|
| How traffic moves | All at once | Instance by instance | A small share first, then more |
| Old and new live together | Only during draining | Yes, during the rollout | Yes, by design |
| Extra capacity | A second full copy | A few surge instances | A few canary instances |
| Rollback | Switch back | Roll back instance by instance | Stop the canary |
| Best for | Clean cut-overs, single servers | Many identical instances | Heavy traffic with good monitoring |

Rule of thumb: blue-green when you want a clean switch and a fast way back; canary when you want real users to test the change before everyone does. The **[Kubernetes Deployment docs](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)** cover the rolling side in detail.

## The Database Problem (and the Fix)

Blue and green usually share one database. Right after the switch, the new code writes to it; after a rollback, the old code reads what the new code wrote. If a migration renamed or dropped a column, one of them breaks.

The fix is to make every schema change backward compatible, using **expand and contract** (also called **[parallel change](https://martinfowler.com/bliki/ParallelChange.html)**):

1. **Expand:** add the new column or table; don't remove anything.
2. **Migrate:** deploy code that uses the new structure and still copes with the old one.
3. **Contract:** remove the old structure in a later release, when no live or kept version reads it.

Follow it and both blue and green work at every step, so the rollback stays safe.

## When Not to Use Blue-Green Deployment

Blue-green is not always the right tool:

- **You need gradual exposure.** If a change is risky and you want 5% of users on it first, use a canary.
- **The app can't run twice.** Something that holds an exclusive lock, a single scheduled job, or a fixed port it can't move off needs work before two copies can run.
- **Your schema change can't be split.** A migration that breaks the old code makes rollback a lie. Split it first.
- **A short gap is fine.** For an internal tool used by three people, the simplest deploy wins.
- **You haven't tested the change at all.** Blue-green makes a bad release quick to undo, not harmless. Try it on a **[staging site](/how-to-setup-staging-site-guide/)** first.

## Blue-Green Deployment in xCloud, Without the Plumbing

xCloud's **Release mode** does the single-server version of blue-green for you, from the dashboard:

- **Node.js apps on nginx:** each release starts on a second port, must pass a health check, then nginx switches over and the old process finishes its requests.
- **Docker containers** built from a Dockerfile or an app recipe: the new container starts beside the old one on a second port and takes over after its health check.
- **PHP, Laravel and WordPress:** release folders with a link switch, plus shared `.env`, `storage` and uploads.
- **Rollback in one click:** the last five releases (three images for containers) are kept on the **Release mode** card.

![A Node.js app's releases on the xCloud Release mode card after a rollback: the older release is Live again, other kept releases show a Rollback button](/_landing/blog/blue-green-deployment-image-2.png)

When you click **Rollback**, xCloud asks you to confirm: "The site switches to this release at once. The database, .env and shared files are not changed." For Node.js and containers, the older release starts on the idle port before nginx moves traffic to it, so a rollback is a blue-green switch too.

![Rolling back a Node.js app in xCloud: the site switches to the older release, the database, .env and shared files are not changed](/_landing/blog/blue-green-deployment-image-3.png)

What it doesn't do: canary releases, rolling updates across several servers, or blue-green for a repository's own **[docker-compose file](/what-is-docker-compose/)**. It is built for the most common setup, an app on one server.

👉 Turn it on: **[Zero-downtime deploys with Release mode](/docs/zero-downtime-deploys-with-release-mode-in-xcloud/)** · **[How to roll back a deployment](/docs/roll-back-a-deployment-in-xcloud/)** · **[Deploy a Node.js application](/docs/how-to-deploy-a-node-js-application/)**.

## Try a Blue-Green Deployment This Week

**Blue-green deployment** is the simplest way to release without downtime and undo a bad release in seconds: two copies, a health check, one switch, and the old copy kept as your way back. Add connection draining and backward-compatible migrations, and the switch becomes invisible to visitors.

If your app runs on one server, you don't need a second data center or a pipeline to get it. Deploy it on **[Node.js hosting](/node-js-hosting/)** or **[Docker hosting](/docker-hosting/)** with xCloud, turn on Release mode, and watch your next deploy go live without a single failed request. See the **[zero-downtime deployments page](/zero-downtime-deployments/)** for every stack it covers, and the **[launch post](/zero-downtime-deploys-and-one-click-rollback/)** for our full test results.

If you have found this blog helpful, feel free to [**subscribe to our blogs**](https://xcloud.host/blog/) for valuable tutorials, guides, knowledge, and tips on web hosting and server management. You can also join our [**Facebook community**](https://www.facebook.com/groups/xcloud.community) to share insights and engage in discussions.

## Frequently Asked Questions

### What is a blue-green deployment?

A blue-green deployment runs two copies of your app. One (blue) serves all traffic while you deploy and check the new version on the other (green). Then a router or proxy moves all traffic to green in one step, and blue stays ready as an instant rollback.

### Is blue-green deployment zero downtime?

It can be. The switch itself is instant, but you also need a health check before it, and you need to let the old copy finish requests already in progress. With both in place, visitors see no failed requests.

### What is the difference between blue-green and canary deployment?

Blue-green moves all traffic to the new version at once. A canary sends a small share of users to the new version first, watches for problems, and grows the share step by step.

### How do you handle the database in a blue-green deployment?

Usually both copies share one database, so schema changes must work with the old and the new code. Use the expand and contract pattern: add new structures first, switch the code, and remove old structures in a later release.

### Can I do blue-green deployment on a single server?

Yes. Run the new version on a second port, check that it answers, then point your reverse proxy at the new port and let the old process finish its requests. xCloud's Release mode does this for Node.js apps and Docker containers on one server.

### Does xCloud support blue-green deployments?

Yes, through Release mode. Node.js apps and Docker container sites start each release on a second port and switch after a health check. PHP and WordPress sites use release folders, the single-server version of the same idea. Both keep older releases for a one-click rollback.
