A blue-green deployment is the most boring way to achieve zero-downtime releases, and that’s precisely why it’s so effective.
Imagine your entire application, all of it, running on a set of servers we’ll call "Blue." This is your current live production environment. Everything is humming along, users are happy. Now, you want to deploy a new version.
Instead of touching the Blue servers, you spin up an entirely separate, identical set of servers, let’s call this "Green." You deploy your new version to Green. It’s completely isolated, no users are hitting it. You can test it, smoke-test it, run integration tests, whatever you need.
Here’s a simplified diagram of what that looks like:
+-----------------+ +-----------------+
| Load Balancer | ----> | Blue Servers | (Production)
+-----------------+ +-----------------+
(Old Version)
+-----------------+ +-----------------+
| Load Balancer | ----> | Green Servers | (Staging/New)
+-----------------+ +-----------------+
(New Version)
Once you’re confident Green is ready, the magic happens. You simply flip a switch on your load balancer. Instead of sending traffic to Blue, it starts sending all new traffic to Green.
+-----------------+ +-----------------+
| Load Balancer | ----> | Blue Servers | (Idle/Rollback)
+-----------------+ +-----------------+
(Old Version)
+-----------------+ +-----------------+
| Load Balancer | ----> | Green Servers | (Production)
+-----------------+ +-----------------+
(New Version)
The switch is usually a DNS change or a load balancer configuration update. For a load balancer, this might mean changing a backend pool’s health check settings or simply rerouting traffic. If you’re using something like AWS Elastic Load Balancer (ELB), you’d update your target groups.
Let’s say you’re using Nginx as a reverse proxy. Your nginx.conf might look something like this for the Blue environment:
http {
upstream blue_app {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
# ... more blue servers
}
upstream green_app {
server 10.0.2.20:8080;
server 10.0.2.21:8080;
# ... more green servers
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://blue_app; # Initially points to Blue
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
To switch to Green, you’d simply change proxy_pass http://blue_app; to proxy_pass http://green_app; and reload Nginx (sudo systemctl reload nginx). The old Blue servers are still running, but they’re not receiving any live traffic. This is your instant rollback path. If something goes wrong with Green, you just flip the switch back to Blue.
The key here is that the switch is atomic. All new requests go to the new version simultaneously. Existing requests on the old version will complete without interruption. This is what achieves zero downtime. The old environment isn’t destroyed; it’s kept warm and ready as a fallback.
This works for any monolith. Whether it’s a Java Spring Boot app, a Ruby on Rails app, or a Node.js Express app, as long as it can be deployed to a set of servers and routed through a load balancer, blue-green works. You’re not changing the application’s internal architecture; you’re changing how traffic reaches it.
The "Green" environment doesn’t need to be a perfect mirror of production in terms of load, but it does need to be identical in terms of the application code and its dependencies. You might provision fewer servers for Green if you’re confident in its performance, or you might provision the same number for a more rigorous test. The crucial part is that the application code and its configuration are the same.
The biggest challenge isn’t the deployment itself, but managing the state and data. If your monolith has a shared database, you need to ensure backward compatibility of the database schema between the Blue and Green versions. The Green version must be able to write data that the Blue version can still read, and vice-versa, during the transition and rollback period. This often means that database migrations are applied before deploying the Green environment, and the Green version is designed to work with the new schema. You can’t easily roll back a database schema change.
Once you’re absolutely certain Green is stable, you can then decommission the Blue servers to save costs. This can be done hours, days, or even weeks later.
The next hurdle you’ll likely encounter is managing database migrations alongside this strategy, especially when dealing with schema changes that aren’t backward compatible.