Kubernetes Deployments vs StatefulSets: When to Use Each
Understand the real differences between Deployments and StatefulSets in Kubernetes. Learn which workloads belong in each, with concrete YAML and rollout behavior.
What you'll learn
- ✓What a Deployment guarantees and what it does not
- ✓Why StatefulSets exist and what stable identity means
- ✓How pod naming and DNS differ between the two
- ✓How rolling updates behave in each controller
- ✓A simple rule for picking the right one
Prerequisites
- •Comfortable with the Linux command line
A common moment of confusion when learning Kubernetes is hitting two controllers that both run pods on your behalf and wondering which one to pick. Deployments are the workhorse for stateless services like web apps and APIs. StatefulSets exist for workloads that need a stable identity, ordered startup, or persistent per-pod storage — think databases, message brokers, and clustered caches. The distinction is not academic; the wrong choice will bite you during the first rolling update.
Deployments in one breath
A Deployment manages a ReplicaSet, which in turn manages Pods. The Pods are interchangeable. Each one gets a randomly suffixed name like web-7d9c4f8b6d-xk2vp. If a node dies, the scheduler launches a replacement somewhere else and nobody cares which pod handles the next request.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
Updates roll out by spinning up new pods and tearing down old ones, in parallel batches controlled by maxSurge and maxUnavailable. It is fast, simple, and exactly what you want for a stateless workload.
What Deployments do not give you
Three things, mainly. First, no stable network identity — when a pod is replaced, its name and IP change. Second, no ordered startup — pods come up in whatever order the scheduler finds room for. Third, no per-pod persistent storage — if you attach a PersistentVolumeClaim to a Deployment, every replica shares it, which is rarely what a database wants.
If those properties matter, you need a StatefulSet.
StatefulSets in one breath
A StatefulSet also manages Pods, but with three additional guarantees: stable network identity, ordered deployment and termination, and per-pod persistent storage via volumeClaimTemplates.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
spec:
serviceName: db-headless
replicas: 3
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: db
image: postgres:16
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
The pods are named db-0, db-1, db-2 — not random. Each one gets its own PVC named data-db-0, data-db-1, data-db-2. They start in order (0 before 1 before 2) and terminate in reverse. Combined with a headless Service, each pod gets a DNS name like db-0.db-headless.default.svc.cluster.local, which is how cluster members find each other.
Rolling updates differ
A Deployment rolls all pods in parallel up to the maxSurge and maxUnavailable settings. Fast, but unpredictable order.
A StatefulSet rolls pods one at a time, starting from the highest ordinal and working down. Pod db-2 is updated and must reach Ready before db-1 begins. This matters because clustered databases often need a controlled rollout to maintain quorum.
Headless Services and DNS
StatefulSets are almost always paired with a headless Service, declared by setting clusterIP: None. Instead of one virtual IP that load-balances across pods, the Service publishes an A record per pod.
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None
selector:
app: db
ports:
- port: 5432
Now a client can connect to a specific replica by name, which is exactly what replication setups expect.
Scaling
Scaling a Deployment up or down is essentially free — pods are fungible. Scaling a StatefulSet is more delicate. Scaling up adds the next ordinal and provisions a new PVC. Scaling down terminates the highest ordinal but does not delete the PVC, on purpose — you might want the data back. Cleaning up storage after scale-down is a manual step you have to remember.
The simple decision rule
Ask one question: does this workload care which pod it is? If the answer is no, you want a Deployment. If the answer is yes — because it has a name in a cluster config, because it owns its own slice of data, because order matters — you want a StatefulSet.
kubectl get deploy
kubectl get sts
Run those side by side on a healthy cluster and you will usually see Deployments running web tier and API tier workloads, and StatefulSets running the data tier. That pattern is the default for a reason.
Pick the right controller up front and you avoid a painful migration later. Pick wrong and you will find out the first time a node reboots.
Related articles
- DevOps Kubernetes Pods vs Deployments
How Pods, ReplicaSets, and Deployments relate, why you almost never create Pods directly, and how rolling updates and rollbacks actually happen.
- DevOps Kubernetes Services Explained: ClusterIP, NodePort, LoadBalancer
A clear guide to Kubernetes Services. Learn what ClusterIP, NodePort, LoadBalancer, and headless Services do, and when to use each in real clusters.
- Docker Docker Compose vs Kubernetes: When to Use Which
A pragmatic comparison of Docker Compose and Kubernetes covering scope, operational cost, and the signals that tell you it is time to graduate.
- Kubernetes Kubernetes Init Containers: A Practical Tutorial
Learn how Kubernetes init containers work, when to use them for setup tasks, and how to build robust pod initialization pipelines with real YAML examples.