🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

What Is Immutable Infrastructure? Explained Simply

Instead of patching a running server, you replace it entirely with a new one built from a known-good image. Here's what immutable infrastructure actually means, why it matters, and how containers made it the default.

DevOpsBoysJun 18, 20264 min read
Share:Tweet

Immutable infrastructure means servers (or containers) are never modified after they're created. If something needs to change — a config update, a security patch, a new app version — you build a new instance from scratch and replace the old one, instead of logging in and changing it live.

The Old Way: Mutable Infrastructure

bash
# The traditional approach — SSH in, change things directly on a live server
ssh prod-server-01
sudo apt update && sudo apt upgrade -y
sudo vim /etc/nginx/nginx.conf
sudo systemctl restart nginx

This works, but every server that's been manually touched like this drifts further from any documented state over time. Six months in, nobody fully knows what's actually configured on prod-server-01 versus prod-server-02 — they were provisioned identically once, but accumulated different ad-hoc changes since.

This is "configuration drift," and it's the core problem immutable infrastructure exists to solve.

The Immutable Way

dockerfile
# Instead of patching a running container, you change the Dockerfile 
# and build a completely new image
FROM node:22-slim
COPY package.json .
RUN npm install
COPY . .
CMD ["node", "server.js"]
bash
# Build a new image — the old one is never touched
docker build -t myapp:v47 .
 
# Deploy the new image — replace the running container entirely
kubectl set image deployment/myapp myapp=myregistry.io/myapp:v47

The old container isn't patched and kept running — it's terminated, and a brand new container starts from the new image. There's no "current state plus changes" to track. The image is the complete, exact state.

Why This Actually Matters

No configuration drift. Every instance running myapp:v47 is byte-for-byte identical, because they were all built from the same image. There's no possibility of "server A has a manual fix that server B doesn't" because manual fixes to a running instance simply don't happen.

Rollback is trivial and reliable. Rolling back means deploying the previous image, not trying to reverse a series of manual changes whose exact order and effect you may not remember.

bash
kubectl rollout undo deployment/myapp
# This works reliably specifically BECAUSE the previous state is 
# a complete, known image — not a delta from an unknown starting point

Testing is meaningful. If you tested myapp:v47 in staging, and production deploys the exact same image, you know production is running what you actually tested — not "production with v46 plus three hotfixes that staging never saw."

Security patching becomes systematic. Instead of patching N running servers individually (and hoping you didn't miss one), you rebuild the base image with patches applied and redeploy everywhere — every instance gets the fix because every instance is freshly built from the patched image.

How Different Layers Apply This Principle

Container images are the most common application of immutable infrastructure today — this is the default behavior, not an extra discipline you have to maintain, because Docker/OCI images are inherently immutable once built.

VM images (AMIs, machine images) apply the same idea at the VM level — instead of patching a running EC2 instance, you build a new AMI with Packer, then replace instances using that AMI through an Auto Scaling Group rolling update.

hcl
# Terraform — referencing an immutable AMI built by Packer, 
# never modifying instances directly
resource "aws_launch_template" "app" {
  image_id      = data.aws_ami.app_v47.id  # built fresh for each release
  instance_type = "t3.medium"
}

Infrastructure itself (via IaC) extends the same principle — instead of manually changing a cloud resource's config through a console, you change Terraform code and apply it, so the resource's actual state always traces back to version-controlled code, not someone's memory of what they clicked.

The One Place Mutability Still Lives

Data. Databases, persistent volumes, and stateful storage are deliberately not immutable — you can't "replace" a database with a fresh one without losing the data inside it. Immutable infrastructure principles apply cleanly to compute (servers, containers) but databases need their own discipline (migrations, backups, careful schema versioning) rather than the rebuild-and-replace pattern.

Immutable:    application servers, containers, VM images, load balancer configs
Mutable:      databases, persistent volumes, object storage contents

Confusing these two categories is a common mistake — trying to apply "just rebuild it" thinking to a stateful database leads to data loss, not a clean redeploy.

Why Containers Made This the Default, Not a Discipline

Before containers, immutable infrastructure required deliberate process discipline — teams had to actively choose to rebuild VMs instead of SSH-patching them, and it was easy to slip back into old habits under deadline pressure. Containers made the immutable pattern the easy path and mutation the hard path (you'd have to deliberately break the container abstraction to modify a running instance), which is a large part of why immutable infrastructure went from "best practice some teams follow" to "just how things work" once containers became standard.

See this principle in action: What Is a Container Image Layer — Explained

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments