How you replace the old version of an app with the new one determines whether users see downtime, how quickly you can roll back, and how much infrastructure you need. Here are the main deployment strategies, what they cost, and how to implement them on VPS servers.

At a glance

Strategy Downtime Rollback speed Extra resources Complexity
Recreate Yes (seconds to minutes) Redeploy old version None Lowest
Rolling No (with health checks) Medium Little Low–medium
Blue-green No Instant (switch back) 2× during deploy Medium
Canary No Fast (shift traffic back) Some Higher
Feature flags No Instant (toggle) None Code-level

Recreate

Stop the old version, start the new one. A plain docker compose up -d with one container does this. It’s fine for internal tools, low-traffic sites, or maintenance windows. Show a maintenance page during longer migrations.

Rolling updates

Replace instances one at a time, behind a load balancer, waiting for each new instance to pass health checks:

During the rollout, old and new versions run at the same time, so APIs and database schemas must be compatible with both.

Blue-green

Run two complete environments. Blue serves traffic, green gets the new version. After testing green, switch traffic (Nginx upstream, load balancer, or DNS) to green. Rollback means switching back.

upstream app { server 127.0.0.1:8081; }   # blue
# deploy green on :8082, test it, then:
# upstream app { server 127.0.0.1:8082; } && nginx -s reload

Detailed guide: blue-green deployment and zero-downtime Node.js deploys.

Canary releases

Send a small share of traffic (say 5%) to the new version, watch error rates and latency, then increase gradually. With Nginx:

upstream app {
    server 10.0.0.11:8080 weight=19;   # stable
    server 10.0.0.12:8080 weight=1;    # canary (~5%)
}

Kubernetes ingress controllers, service meshes, and tools like Argo Rollouts automate weighted canaries. Canaries need good monitoring, or you won’t notice problems. See observability basics.

Feature flags

Deploy code with new features switched off, then enable them for internal users, a percentage, or everyone, without redeploying. They separate deploying from releasing, and make rollback a toggle. See feature flags.

Database migrations: the hard part

Code rolls back easily, and data doesn’t. Use expand and contract:

  1. Expand: add new columns or tables in a backwards-compatible way (old code still works).
  2. Deploy code that writes to both, or reads the new structure.
  3. Backfill data.
  4. Contract: remove old columns in a later release, once nothing uses them.

Always back up before migrations. See database backup automation.

Rollbacks

  • Deploy immutable versions (image tags, Git tags), so “previous version” is unambiguous. See Git tags and releases.
  • Keep the previous version ready (old containers, the blue environment, the previous ReplicaSet).
  • Practise rollbacks, and know which migrations are reversible.

Choosing for a VPS setup

Situation Strategy
Single VPS, small app Recreate in a quiet window, or blue-green with two containers
Two+ app servers behind Nginx Rolling (one server at a time)
Critical changes, real traffic Canary + monitoring
Big features Feature flags
Kubernetes Rolling (default), canary with ingress/Argo Rollouts

Quick reference

Strategy Key idea
Recreate Stop old, start new
Rolling Replace instances gradually
Blue-green Two environments, switch traffic
Canary Small % first, then increase
Feature flags Deploy dark, release by toggle

Related: CI/CD pipeline explained and Nginx load balancing.

  • DevOps
  • Deployment
  • CI/CD