Skip to main content
Mutable vs Immutable Infrastructure: What's the Difference?

Mutable vs Immutable Infrastructure: What's the Difference?

Key Takeaway

Mutable vs immutable infrastructure compared. Learn the differences, when to use each, and how tools like Terraform, Docker, and Ansible fit in.

Table of Contents

Introduction

When you deploy a server, can you change it later — or do you throw it away and build a new one? That’s the core question behind mutable vs immutable infrastructure.

Mutable: You deploy a server and modify it over time (patches, config changes, updates). Immutable: You deploy a server and never change it. Need an update? Build a new one, replace the old one.

Most modern infrastructure leans immutable, but both approaches have their place. Here’s when to use each.

Quick Comparison

MutableImmutable
ChangesModify servers in placeReplace servers entirely
Config driftLikely over timeImpossible by design
RollbackComplex (undo changes)Simple (deploy previous version)
ToolsAnsible, Chef, Puppet, SSHTerraform, Docker, Packer, Kubernetes
Deploy speedFast (small changes)Fast (swap instances)
StateServers are uniqueServers are disposable
ScalingCopy server + apply scriptsLaunch from image
Best forLegacy systems, stateful serversMicroservices, cloud-native apps

Mutable Infrastructure

In mutable infrastructure, servers are updated in place after deployment. You SSH in, apply patches, change configurations, restart services.

How It Works

Day 1: Deploy Ubuntu 22.04 server
Day 30: apt update && apt upgrade (security patches)
Day 60: Change nginx config, restart nginx
Day 90: Install monitoring agent
Day 120: Update application to v2.0

The server accumulates changes over time. Each server becomes unique based on its history.

Real-World Example: Ansible

Ansible is the most popular mutable infrastructure tool. It connects to existing servers and applies changes:

# ansible playbook — modify servers in place
- hosts: webservers
  tasks:
    - name: Update packages
      apt:
        upgrade: dist
        update_cache: yes

    - name: Install nginx
      apt:
        name: nginx
        state: present

    - name: Deploy app config
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: restart nginx

The Configuration Drift Problem

The biggest risk with mutable infrastructure is configuration drift — servers that should be identical gradually become different:

Server A: Ubuntu 22.04, nginx 1.22, Node 18, monitoring agent v2
Server B: Ubuntu 22.04, nginx 1.24, Node 20, monitoring agent v3
Server C: Ubuntu 22.04, nginx 1.22, Node 18, no monitoring agent (someone forgot)

All three servers were supposed to be identical. Over months of manual patches and hotfixes, they diverged. Now a deployment that works on Server A fails on Server B. This is the “snowflake server” problem.

When Mutable Makes Sense

  • Stateful servers: Database servers that can’t be easily replaced
  • Legacy applications: Apps that weren’t designed for containerization
  • Quick hotfixes: Emergency patches that need to go out immediately
  • Small teams: When the overhead of building images isn’t justified
  • Compliance: When you need to prove exactly what changed and when

Immutable Infrastructure

In immutable infrastructure, servers are never modified after deployment. Every change produces a new server image, and the old server is destroyed.

How It Works

v1.0: Build image → Deploy 3 instances → Running
v1.1: Build NEW image → Deploy 3 NEW instances → Destroy old instances
v1.2: Build NEW image → Deploy 3 NEW instances → Destroy old instances

No SSH, no patching, no config changes. If something needs to change, you build a new version from scratch.

Real-World Example: Terraform + Packer

Step 1: Build a machine image with Packer:

# packer template
source "amazon-ebs" "web" {
  ami_name      = "web-app-{{timestamp}}"
  instance_type = "t3.micro"
  region        = "us-east-1"
  source_ami    = "ami-0c55b159cbfafe1f0"
}

build {
  sources = ["source.amazon-ebs.web"]

  provisioner "shell" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y nginx nodejs",
      "sudo systemctl enable nginx"
    ]
  }

  provisioner "file" {
    source      = "app/"
    destination = "/var/www/app"
  }
}

Step 2: Deploy with Terraform:

# terraform — deploy the immutable image
resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-NEW-VERSION"  # New AMI from Packer
  instance_type = "t3.micro"

  tags = {
    Name    = "web-${count.index}"
    Version = "1.1"
  }
}

Every deployment uses a fresh image. All servers are identical by construction.

Real-World Example: Docker + Kubernetes

Containers are the most common form of immutable infrastructure:

# Dockerfile — immutable by design
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# kubernetes deployment — replace pods, never patch them
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  template:
    spec:
      containers:
        - name: web
          image: myapp:1.1  # New version = new image
          ports:
            - containerPort: 3000

Why Immutable Wins for Most Use Cases

  1. No configuration drift: Every instance is built from the same image
  2. Easy rollback: Deploy the previous image version
  3. Reproducible: Same image works in dev, staging, and production
  4. Testable: Test the image before deploying to production
  5. Secure: No SSH access needed, smaller attack surface
  6. Auditable: Git history shows exactly what changed between versions

When Immutable Makes Sense

  • Stateless web services: API servers, web frontends
  • Microservices: Each service is its own image
  • Auto-scaling: Launch identical instances from an AMI
  • CI/CD pipelines: Build → Test → Deploy image
  • Cloud-native applications: Designed for containers/Kubernetes

Hybrid Approach: Immutable Compute, Mutable Data

Most real-world architectures use both:

┌─────────────────────────────────────────────┐
│  IMMUTABLE (replace, never modify)          │
│  • Web servers (Docker/AMI)                 │
│  • API servers                              │
│  • Worker processes                         │
│  • Lambda functions                         │
└─────────────────────────────────────────────┘
                    ↕
┌─────────────────────────────────────────────┐
│  MUTABLE (update in place)                  │
│  • Databases (RDS, PostgreSQL)              │
│  • File storage (S3, EFS)                   │
│  • Message queues (SQS, RabbitMQ)           │
│  • Caches (Redis, ElastiCache)              │
└─────────────────────────────────────────────┘

Compute is immutable (easy to replace). Data is mutable (needs to persist). This is the standard pattern in modern cloud architecture.

Tool Mapping

ToolApproachWhat It Does
TerraformImmutableProvisions infrastructure (VMs, networks, services)
PackerImmutableBuilds machine images (AMIs, Docker images)
DockerImmutablePackages applications as container images
KubernetesImmutableOrchestrates container deployments
AnsibleMutableConfigures existing servers
ChefMutableConfigures existing servers
PuppetMutableConfigures existing servers

Terraform + Packer + Docker = fully immutable infrastructure pipeline.

Migration Path: Mutable → Immutable

If you’re currently using mutable infrastructure:

  1. Start with containers: Dockerize one application
  2. Build CI/CD pipeline: Automate image builds
  3. Use Terraform: Manage infrastructure as code
  4. Adopt blue-green deploys: Run old and new versions simultaneously
  5. Remove SSH access: Once everything is automated, disable manual access
  6. Scale: Apply the pattern to more services

Hands-On Courses

Learn by doing with interactive courses on CopyPasteLearn:

Conclusion

Immutable infrastructure is the modern standard for cloud-native applications: build an image, test it, deploy it, never modify it. Mutable infrastructure still works for stateful systems and legacy applications. Most production environments use both — immutable compute (containers, AMIs) with mutable data (databases, storage). Start immutable with Terraform and Docker, use Ansible for the things that genuinely need in-place changes.

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.