
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Shipping stateful BEAM applications without dropping connections requires more than a simple rolling update. Blue-Green Deploys for a Elixir App solve the specific challenge of maintaining long-lived WebSocket channels and GenServer state during version transitions by running two identical production environments in parallel. This approach eliminates the "drain timeout" failures common in Phoenix deployments and provides an instant, deterministic rollback mechanism that rolling updates cannot match. If you are managing critical real-time systems, understanding this pattern is essential before considering alternatives like canary or rolling strategies.
Why choose Blue-Green Deploys for a Elixir App over rolling updates?
The Erlang VM (BEAM) is famous for reliability, but its deployment characteristics differ fundamentally from stateless HTTP services like Go or Node.js. Elixir applications, particularly those built with Phoenix LiveView or custom GenServers, maintain significant in-memory state. During a standard Kubernetes rolling update, pods are terminated sequentially. Even with preStop hooks and graceful shutdown periods, there is an inherent window where clients may reconnect to a terminating pod or experience interrupted TCP streams.
Blue-Green Deploys for a Elixir App address this by decoupling deployment from activation. The new version spins up completely independently, establishes its own supervision trees, warms up caches, and connects to external services before receiving a single user request. This is critical for teams needing to meet strict SLOs; as discussed in defining meaningful SLIs and SLOs, eliminating deployment-induced error spikes is often the easiest win for improving availability metrics.
- Zero Connection Drops: Existing WebSocket clients stay on Blue until they naturally disconnect or are explicitly migrated; no forced RST packets during switchover.
- Deterministic Rollback: Reverting is a metadata change at the Ingress level, not a re-deployment. Recovery time objective (RTO) drops from minutes to seconds.
- Full Validation Window: You can run integration tests against the Green environment using production data patterns without risking user impact.
- State Isolation: Avoids the "mixed version" state where some nodes run v1.7.10 and others v1.7.11, which can cause subtle message passing failures in distributed Elixir clusters.
How do you configure Kubernetes Services for Blue-Green Deploys for a Elixir App?
The implementation relies on label selectors rather than multiple physical clusters. You maintain two Deployments (myapp-blue and myapp-green) and a single Service that acts as the traffic switch. The key is ensuring your Elixir application exposes a robust health endpoint that verifies not just HTTP responsiveness, but actual BEAM readiness.
Define Separate Deployments with Version Labels
Your Helm chart or Kustomize overlay should parameterize the color label. Never use the same Deployment object and try to update it in place; that triggers a rolling update. Instead, create distinct resources.
<!-- k8s/deployment-green.yaml -->
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-green
labels:
app.kubernetes.io/name: myapp
deploy.color: green
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: myapp
deploy.color: green
template:
metadata:
labels:
app.kubernetes.io/name: myapp
deploy.color: green
spec:
containers:
- name: phoenix
image: registry.example.com/myapp:v1.7.11
ports:
- containerPort: 4000
readinessProbe:
httpGet:
path: /health/ready
port: 4000
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health/live
port: 4000
initialDelaySeconds: 30
periodSeconds: 10 Implement the Traffic Switch Service
The Service selector targets only the active color. During deployment, you apply the new Deployment, wait for readiness, then patch the Service selector. This atomic label update is what makes Blue-Green Deploys for a Elixir App safe.
apiVersion: v1
kind: Service
metadata:
name: myapp-active
spec:
selector:
app.kubernetes.io/name: myapp
deploy.color: green # PATCH THIS VALUE TO SWITCH TRAFFIC
ports:
- protocol: TCP
port: 80
targetPort: 4000
type: ClusterIP A common mistake is relying solely on Kubernetes' default readiness probe. For Elixir, you must implement a custom /health/ready endpoint that checks database connectivity, Redis pool status, and critical GenServer initialization. Without this, the pod reports "Ready" before the application has finished booting, causing early requests to fail. See Kubernetes resource limits and requests for proper sizing to ensure startup completes within probe windows.
How do you handle database migrations during Blue-Green Deploys for a Elixir App?
This is where most Elixir blue-green implementations fail. You cannot have two different application versions writing to incompatible schemas simultaneously. Since both Blue and Green connect to the same PostgreSQL instance during the transition window, your migrations must be backward-compatible.
- Decouple Migration from Release: Run
mix ecto.migrateas a separate Job or initContainer before the Green deployment starts. Never run migrations inside the application startup script during blue-green transitions. - Expand-Contract Pattern: If renaming a column, first add the new column (expand), deploy Green to write to both, then migrate data, then remove the old column (contract) in a subsequent release cycle.
- Idempotent Migrations: Ensure every migration can run safely multiple times. Use
CREATE INDEX IF NOT EXISTSand check for column existence before altering. - Lock Awareness: Ecto migrations acquire advisory locks. If Blue is still running heavy queries, Green's migration job might block. Schedule migrations during low-traffic windows or use
CONCURRENTLYoptions for index creation.
For teams managing complex schema evolution, pairing this with PostgreSQL replication and high availability patterns ensures the migration target itself remains resilient during the dual-write phase. Always test migrations against a restored production snapshot before executing in the blue-green pipeline.
What are the trade-offs compared to other Elixir deployment strategies?
Blue-Green is not free. Understanding the cost-benefit ratio helps you decide when to apply it versus simpler methods. The table below compares approaches specifically for BEAM workloads in 2026.
| Criteria | Blue-Green | Rolling Update | Canary |
|---|---|---|---|
| Downtime Risk | Near-zero (atomic switch) | Moderate (drain race conditions) | Low (limited blast radius) |
| Resource Cost | 2x peak capacity required | ~1.2x (surge factor) | 1.1x–1.5x (subset) |
| Rollback Speed | Instant (selector revert) | Slow (re-deploy previous image) | Moderate (shift weight back) |
| State Handling | Isolated (clean slate) | Mixed versions coexist | Mixed versions coexist |
| Complexity | Medium (infra duplication) | Low (native K8s) | High (traffic splitting + metrics) |
| Best For | Critical real-time / financial | Stateless APIs / batch | User-facing feature validation |
In practice, I reserve Blue-Green Deploys for a Elixir App for systems where connection stability directly impacts revenue or compliance. For internal tools or batch processors, rolling updates with proper preStop hooks are sufficient. The 2x resource cost is significant for Nepal-based startups operating on tight NPR budgets, but for global SaaS products serving enterprise clients, the insurance policy against botched releases pays for itself after one prevented outage.
Automating Blue-Green Deploys for a Elixir App Safely
Manual kubectl patching is unacceptable for production. Automate the switch with verification gates. Your CI/CD pipeline should follow this exact sequence:
- Deploy Green: Apply the new Deployment manifest. Wait for
kubectl rollout status deployment/myapp-green --timeout=300s. - Smoke Test: Execute a synthetic transaction suite against the Green service endpoint directly (bypassing the main Ingress). Verify critical paths: auth, DB read/write, WebSocket handshake.
- Switch Traffic: Atomically update the Service selector. Log the timestamp and previous selector value for audit trails.
- Monitor Error Budget: Watch error rates and latency for 5–10 minutes post-switch. If thresholds breach, auto-revert the selector.
- Teardown Blue: Only after the verification window passes, delete the old Deployment. Keep it scaled to zero for 24 hours as a warm backup if storage permits.
Integrate this with your observability stack. As detailed in Prometheus and Grafana full monitoring stack setups, you should have alerts specifically tuned to detect post-deployment anomalies. For Elixir, monitor vm_memory_total, phoenix_channel_join_count, and ecto_query_duration immediately after switchover. Automated rollback triggered by these signals transforms Blue-Green Deploys for a Elixir App from a manual procedure into a self-healing system.
Final Considerations for Production Elixir Systems
Blue-Green Deploys for a Elixir App provide the highest safety guarantee for stateful BEAM workloads, but they demand discipline in migration management and resource planning. Start by implementing the dual-deployment pattern in staging, validate your health checks catch real boot failures, and only promote to production once your automated rollback has been tested under load. The upfront infrastructure cost is the price of predictable releases. If your team needs help designing a compliant, audit-ready deployment pipeline for Elixir or other cloud-native systems, reach out to discuss your architecture.