HPA and VPA are the two built-in ways Kubernetes autoscales a workload, and they change different things. The Horizontal Pod Autoscaler (HPA) changes how many pod replicas run, adding or removing pods as demand shifts. The Vertical Pod Autoscaler (VPA) changes the size of each pod by adjusting its CPU and memory requests. HPA scales out, VPA scales up.
Key Takeaways
- HPA scales out by changing the number of replicas. VPA scales up by changing each pod's CPU and memory requests.
- HPA is built into Kubernetes. VPA is a separate add-on you install, and it needs the Metrics Server.
- Use HPA for stateless services with bursty traffic. Use VPA for stateful or single-instance workloads and to right-size requests that are consistently wrong.
- Do not run HPA and VPA on the same resource metric. Kubernetes explicitly warns against it, because they feed each other into a scaling loop.
- VPA has historically restarted pods to apply a change. In-place pod resize, stable in Kubernetes v1.35, removes that restart for most cases.
What Is Horizontal Pod Autoscaling (HPA)?
The Horizontal Pod Autoscaler (HPA) adjusts the number of pod replicas in a workload based on observed metrics such as CPU, memory, or custom application metrics. So, when demand rises, it adds pods. When demand falls, it removes them. The workload runs more copies of the same pod, and each copy stays the same size.
HPA is built into Kubernetes as a core controller, so there is nothing extra to install. It supports resource metrics like CPU and memory, plus custom, object, and external metrics such as requests-per-second or queue depth (Kubernetes documentation).
The controller checks metrics on a periodic loop, 15 seconds by default, and computes a target replica count from a simple ratio.
The formula is desiredReplicas = ceil[currentReplicas × (currentMetricValue / desiredMetricValue)].
For example, if pods are averaging 200m of CPU against a 100m target, HPA doubles the replica count. It skips scaling when the ratio is within a default tolerance of 0.1, which stops it from reacting to small fluctuations.
HPA fits stateless services that scale out cleanly, such as web frontends, APIs, and queue workers. It handles bursty or wildly unpredictable traffic because adding replicas absorbs a spike faster than resizing a single pod. Running multiple replicas also gives you redundancy if one pod or node fails.
For example, this manifest keeps a web API between 3 and 20 replicas and adds pods whenever the average CPU passes 60 percent.
# Illustrative HPA manifest — confirm the API version against your cluster before use
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-api
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60What Is Vertical Pod Autoscaling (VPA)?
The Vertical Pod Autoscaler (VPA) adjusts how much CPU and memory each pod requests, so its resources match actual usage. It does not change how many pods run. Instead, it makes each pod bigger or smaller so the workload requests what it genuinely needs, rather than a number someone guessed at deploy time.
Unlike HPA, VPA is not built into Kubernetes, so you install it as an add-on and it reads usage data from the Metrics Server.
Once it is running, you choose one of VPA's update modes, and the mode decides whether it only recommends sizes or actually changes pods:
- The safest mode is Off, which produces recommendations and touches nothing.
- The Initial mode applies new sizes only when a pod first starts.
- The Recreate and Auto modes go further and resize pods that are already running.
In those modes, VPA resizes a running pod by recreating it. As the Kubernetes documentation states, "Whenever VPA updates the pod resources, the pod is recreated, which causes all running containers to be recreated."
But recreating a pod means evicting the old one first, and the docs warn that VPA "cannot guarantee that pods it evicts or deletes to apply recommendations will be successfully recreated." If the cluster is short on capacity, the resized pod may not get rescheduled.
Newer modes reduce that risk, though. InPlaceOrRecreate "will first attempt to apply updates in-place, if in-place update fails, VPA will fall back to pod recreation," and InPlace "will attempt to apply resource updates in-place and never fall back to pod eviction" (Kubernetes documentation).
VPA fits stateful or single-instance workloads that cannot scale out, such as databases, and workloads with high startup costs like JVM services or ML inference, where restarting to warm up is expensive.
For example, this VPA object targets a deployment and runs in Off mode, so it produces recommendations without changing any running pod.
# Illustrative VPA object — confirm mode names against your VPA version
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-api
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web-api
updatePolicy:
updateMode: "Off" # recommendation-only, safest place to startHPA vs. VPA Key Differences
The core difference between HPA and VPA is what each one scales. HPA changes the number of pods, and VPA changes the size of each pod. Everything else follows from that one distinction, from which metrics each one reads to how disruptive it is to apply a change.
HPA | VPA | |
What it changes | Number of pod replicas | CPU and memory requests per pod |
Scaling axis | Out and in (more or fewer pods) | Up and down (bigger or smaller pods) |
Trigger metric | CPU, memory, custom, external | Historical CPU and memory usage |
Built into Kubernetes | Yes | No, add-on plus Metrics Server |
Disruption to apply | Low, adds pods alongside existing ones | Recreates the pod in Recreate/Auto mode; in-place in newer modes |
Best workloads | Stateless, bursty, scale-out services | Stateful, single-instance, mis-sized workloads |
Scale to zero | Yes, with KEDA on top | No |
The table makes the decision look binary, but most clusters need both over time. The next two sections cover how to choose for a single workload, and how to combine them without the two conflicting.
When To Use HPA and When To Use VPA
You must choose what to use based on whether a workload can run as multiple identical copies or not. If it can and its load rises and falls, HPA is the right tool. If it cannot, or it is simply the wrong size, VPA is the right tool.
Choose HPA if:
- The workload is stateless and horizontally scalable, for example a REST API or a web frontend.
- Traffic rises and falls, so adding and removing replicas tracks demand.
- You need redundancy, since multiple replicas survive a single pod or node failure.
Choose VPA if:
- The workload is stateful or a single instance, for example a database or a legacy monolith that cannot run as many replicas.
- Startup is expensive, for example a JVM service or an ML model that takes minutes to warm up, so you want the right size rather than more copies.
- The workload is consistently over- or under-provisioned and scaling out does not fix the underlying waste.
The following diagram shows the two questions that decide the autoscaler: whether the workload can scale out, and whether its load changes.

Can You Use HPA and VPA Together?
You can use HPA and VPA together, but not on the same resource metric. Per the documentation, VPA "should not be used with the Horizontal Pod Autoscaler (HPA) on the same resource metric (CPU or memory)" (Kubernetes documentation). If run both on CPU, they cancel each other out.
The conflict comes from how HPA measures load. HPA compares current CPU usage to the request you set, so utilization is usage divided by the request.
When VPA raises the request, utilization drops, because the same usage divided by a bigger request is a smaller percentage. HPA then sees that lower utilization, treats it as spare capacity, and removes replicas. With fewer replicas, each remaining pod does more work, VPA raises the request again, and the replica count keeps increasing and decreasing. This is called flapping.
The following diagram shows the feedback loop that forms when HPA and VPA both act on CPU.

There are two safe patterns:
- Run HPA on a different metric. Point HPA at a custom or external signal such as requests-per-second or queue depth, and let VPA manage CPU and memory, so the two never read the same signal. Custom-metric HPA needs an adapter, for example the Prometheus Adapter, to expose that metric to the autoscaling API.
- Keep VPA in Off mode. VPA only recommends sizes, and you apply those recommendations through your normal deployment while HPA handles replicas.
Stop Hand-Tuning Autoscalers
Sedai right-sizes pods autonomously inside your SLOs.

Limitations of HPA and VPA
Both autoscalers only react. They wait for a threshold to be crossed, so load has already shifted before either one acts. Both also need ongoing manual tuning: because the HPA targets and the VPA requests, the need for tuning with every workload you add. Neither one knows whether a change is safe for a service's latency or its error budget.
VPA also adds a second cost. Outside the newer in-place modes, it recreates a pod to apply a change, and it cannot guarantee the pod reschedules if the cluster is low on capacity. Alternatively, HPA has no view of cost, so it holds more replicas than a workload needs as long as the metric looks fine.
Because neither one ties a scaling decision to an SLO, teams hesitate to cut resources at all, worried that saving money will breach a performance target.
This highlights the need for autonomous right-sizing. Instead of tuning static targets on a schedule, the system watches each workload's real behavior and adjusts CPU and memory continuously; it only ships a change that stays inside the SLO.
This is what we do at Sedai. At Palo Alto Networks, Sedai reduced Kubernetes costs by 46% with zero incidents.
How to Right-Size Pods Without Downtime
You can right-size a running workload without a restart in three ways: in-place pod resize, VPA's in-place modes, or a guarded rolling update. Which one you use depends on your Kubernetes version and how much you want the system to apply on its own.
In-Place Pod Resize
In-place resize lets you change a pod's CPU and memory on a running container. It was beta in Kubernetes v1.33 and became stable, on by default, in v1.35. CPU changes apply with no restart, and v1.35 added best-effort memory decrease with a safety check. A resizePolicy on each resource controls whether a restart is required.
# Illustrative — in-place resize, stable in Kubernetes v1.35. Engineer-review before use.
apiVersion: v1
kind: Pod
metadata:
name: web-api
spec:
containers:
- name: app
image: web-api:1.0
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: NotRequired # memory decrease is best-effort in v1.35VPA in an In-Place mode
To let VPA apply sizes for you without evicting pods, use InPlaceOrRecreate. It tries an in-place update first and only recreates the pod if that fails. You keep VPA applying changes for you without the restart that makes teams wary of it.
Guarded Rolling Update
On older clusters, apply new sizes through a normal rolling deployment protected by a PodDisruptionBudget. Set maxUnavailable: 0 and a small maxSurge so new, correctly sized pods start before the old ones stop.
A PodDisruptionBudget "can only protect against voluntary evictions, not all causes of unavailability", so it guards a rollout and not a node failure.
# Illustrative PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-api-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web-apiWhichever method you use, leave headroom above your p99 usage:
- If you set memory too close to the average and a normal traffic spike triggers an OOMKill.
- If you set CPU below the real baseline and the kernel throttles the workload, which shows up as added latency.
FAQs
If your team is hand-tuning HPA targets and VPA recommendations across dozens of workloads, Sedai right-sizes them autonomously inside SLO guardrails. Keep stability without sacrificing your budget.
