June 25, 2026 · 15 min read · Aizhan Azhybaeva · Updated September 6, 2026

KEDA vs HPA: Kubernetes Event-Driven Autoscaling Compared (2026)

KEDA vs HPA compared for 2026 - how the Horizontal Pod Autoscaler and KEDA differ on metrics, scale-to-zero, event sources, and why KEDA builds on HPA rather than replacing it. Which pod autoscaler should you use?

KEDA vs HPA: Kubernetes Event-Driven Autoscaling Compared (2026)

KEDA vs HPA is not really a versus: use plain HPA when your workload scales on CPU or memory, use KEDA when it scales on an external event or needs to drop to zero, and understand that KEDA runs HPA underneath either way. The Horizontal Pod Autoscaler (HPA) is built into Kubernetes and scales pods on CPU, memory, and custom metrics. KEDA is a CNCF-graduated project that adds event-driven autoscaling on 70+ external sources plus scale-to-zero. The most important thing to understand up front: KEDA does not replace HPA - it builds on top of it.

This guide compares KEDA and HPA on what actually matters for cost and responsiveness: the metrics each can scale on, event-source support, scale-to-zero, operational complexity, and exactly when to use each.

The short answer

Pick HPA if:

  • Your workloads scale cleanly on CPU, memory, or a custom metric you already expose
  • You do not need to drop to zero replicas when idle
  • You want zero extra components - HPA is built into Kubernetes
  • Your scaling signals are internal resource utilization, not external events

Pick KEDA if:

  • You need to scale on external events - Kafka consumer lag, RabbitMQ / SQS queue depth, Prometheus queries, cron schedules, and 70+ more
  • You want scale-to-zero so idle workloads cost nothing until work arrives
  • You run queue consumers, batch processors, or event-driven microservices
  • You want event-driven scaling without hand-building custom metrics adapters

Both are valid when: they always are - using KEDA means you are using HPA too. KEDA creates and manages a standard HPA for every ScaledObject. The real choice is whether you drive that HPA directly with resource metrics, or let KEDA drive it with external events.

Deciding factors at a glance

If your priority is…Choose
Simple CPU / memory scalingHPA
Scale on Kafka lag, queue depth, or PrometheusKEDA
Scale-to-zero for idle workloadsKEDA
Nothing extra to installHPA
Cron / schedule-based scalingKEDA
Custom metrics without building adaptersKEDA
Maximum simplicity for steady web trafficHPA

The scaling decision flowchart

Work through these in order and stop at the first match. This is the same sequence we walk clients through in an autoscaling review, and it resolves nearly every workload in under a minute.

  1. Does this workload need to run zero pods when idle? If yes, stop here: KEDA. Plain HPA cannot go below one replica, so there is no configuration that gets you there. If no, continue.
  2. Is the signal that should drive scaling external to the pod? Queue depth, Kafka consumer lag, unprocessed SQS messages, a Prometheus query, a row count, a schedule. If yes: KEDA. Backlog should add pods before CPU reacts, and CPU often never reacts at all on an I/O-bound consumer. If no, continue.
  3. Does load correlate cleanly with CPU or memory? Test this honestly rather than assuming it. If yes: HPA, with nothing to install. If no, continue.
  4. Do you already run a metrics adapter such as Prometheus Adapter, with the metric you need already exposed? If yes: HPA on that custom metric is reasonable and avoids a new component. If no, continue.
  5. Would you need to build and operate a metrics adapter to make HPA work here? If yes: KEDA, because it bundles that plumbing for 70+ sources and you would be rebuilding it by hand otherwise.
  6. Is this a batch job rather than a long-running service? If yes: KEDA ScaledJob, not a ScaledObject and not an HPA. ScaledJobs scale Kubernetes Jobs per unit of work instead of adjusting a Deployment’s replica count.
  7. Still unsure? Default to HPA. It is already in the cluster, it is trivially auditable, and moving a workload from HPA to KEDA later is a small change. Adopting KEDA for a workload that did not need it is the more expensive mistake.

One rule sits above all seven: exactly one autoscaling controller per Deployment. Whichever branch you land on, do not leave a second one pointed at the same workload.

What each tool is

Horizontal Pod Autoscaler (HPA)

The Horizontal Pod Autoscaler is a built-in Kubernetes controller (autoscaling/v2) that adjusts the replica count of a Deployment, StatefulSet, or other scalable resource to keep an observed metric near a target. Out of the box it scales on CPU and memory using the metrics server. With a metrics adapter (for example the Prometheus Adapter) it can also scale on custom and external metrics via the Kubernetes metrics APIs.

HPA’s minimum replica count is one - it cannot scale a workload to zero. It is the standard, zero-install answer for workloads whose load correlates well with resource utilization: web frontends, APIs, and most request-driven services.

KEDA

KEDA (Kubernetes Event-Driven Autoscaling) is a CNCF-graduated project that adds event-driven autoscaling to Kubernetes. You declare a ScaledObject that references your Deployment and one or more triggers (scalers). KEDA ships 70+ scalers for sources like Kafka, RabbitMQ, AWS SQS, Azure Service Bus, NATS, Google Pub/Sub, Prometheus, Datadog, CloudWatch, databases, cloud storage, and cron.

Crucially, KEDA is an HPA extension, not a competitor. For each ScaledObject it creates and manages a standard HPA and acts as an external metrics adapter feeding that HPA values from your event source. KEDA’s own controller adds the scale-to-zero transition - activating from 0 to 1 (and back to 0) based on the event source - while the managed HPA handles ongoing scaling between its minimum and maximum.

KEDA vs HPA: head-to-head

DimensionKEDAHPA
What it isCNCF project that extends HPA with event-driven scalingBuilt-in Kubernetes controller
RelationshipCreates and manages an HPA under the hoodThe autoscaling primitive KEDA builds on
Metrics out of the box70+ event sources via scalersCPU and memory
Custom / external metricsBuilt in per scaler, no adapter wiringNeeds a metrics adapter you deploy and maintain
Scale-to-zeroYes - activates from 0 on first eventNo - minimum is one replica
Event sourcesKafka, queues, Prometheus, cron, DBs, cloud, moreNone natively; only what an adapter exposes
Install footprintDeploy KEDA operator + CRDsNone - part of Kubernetes
Best forEvent-driven, bursty, scale-to-zero workloadsSteady, resource-correlated workloads
MaturityCNCF graduated, production-provenCore Kubernetes, extremely mature

The defining contrast: HPA scales on internal resource utilization and never reaches zero; KEDA turns external events into autoscaling signals and adds scale-to-zero, doing so by managing an HPA for you rather than reinventing the scaling loop.

Scale-to-zero: how it actually works

Scale-to-zero is the single feature that makes this a real comparison rather than a preference, so it is worth understanding the mechanism rather than the marketing.

HPA structurally cannot do it. The Horizontal Pod Autoscaler’s minimum is one replica. There is no annotation, no feature gate, and no adapter that changes this. If a workload must sit at zero pods when idle, plain HPA is out of the question and the decision is already made.

KEDA splits the job in two. The HPA that KEDA creates owns scaling between one and N replicas, exactly as it always has. KEDA’s own controller owns the two transitions HPA cannot express. It polls your trigger on pollingInterval (30 seconds by default). When a trigger goes active from an idle state, KEDA scales the Deployment from 0 to 1 and then hands ongoing scaling to the HPA. When every trigger has reported inactive for the length of cooldownPeriod (300 seconds by default), KEDA patches the replica count back to 0 directly, deliberately going around the HPA rather than through it.

The knobs that matter

FieldDefaultWhat it controls
pollingInterval30sHow often KEDA queries the trigger. Directly sets your worst-case wake-up delay from zero
cooldownPeriod300sHow long all triggers must be inactive before scaling back to zero. Too short causes thrash, too long wastes capacity
initialCooldownPeriod0sGrace period after a ScaledObject is created before the first scale to zero
minReplicaCount0The floor the managed HPA scales down to. Set to 1 to keep KEDA’s event scaling without scale-to-zero
maxReplicaCount100The ceiling. Worth lowering deliberately, since a queue backlog will happily ask for all 100
idleReplicaCountunsetReplica count while idle instead of zero. Must be lower than minReplicaCount
activationThresholdper scalerThe 0 to 1 decision, separate from the scaling threshold

The activation threshold footgun

This one catches people. A scaler has two numbers, and they do different jobs. threshold drives scaling from 1 to N. activationThreshold decides whether the scaler is active at all, which is the 0 to 1 question. Activation wins when they disagree.

Set threshold: 10 and activationThreshold: 50 on a queue scaler, then put 40 messages in the queue. The HPA maths says four replicas. KEDA says the scaler is not active, and the workload stays at zero. The messages sit there. If your queue consumer mysteriously refuses to wake up, this pair of numbers is the first place to look.

What scale-to-zero actually saves

Only what your node autoscaler reclaims. Dropping a Deployment to zero pods frees a scheduling slot, not a bill. The saving lands when the emptied node drains and gets removed, which is why pod-level scale-to-zero and node-level autoscaling are one project, not two. Pair KEDA with a node autoscaler and tune them together, as covered in our companion guide on Karpenter vs Cluster Autoscaler.

The savings are largest where the per-pod cost is highest, which in 2026 means GPU inference workloads. A model server holding a GPU while idle is the most expensive idle pod in your cluster, and it is the strongest single argument for KEDA in an AI/ML platform.

The cold-start tax you are accepting

The first unit of work after an idle period pays for: up to one pollingInterval of detection delay, plus pod scheduling, plus node provisioning if no node has room, plus image pull, plus application startup. For a small stateless consumer that is seconds. For a model server pulling a multi-gigabyte image and loading weights, it can be minutes.

That tax is fine for a queue consumer where nobody is watching a spinner. It is not fine on a synchronous user-facing request path. Mitigations worth knowing: shorten pollingInterval for faster detection, pre-pull images onto nodes, set minReplicaCount: 1 for the latency-sensitive subset of your services, or use the KEDA HTTP add-on for HTTP workloads, which holds the incoming request while the first pod starts instead of failing it.

The rule of thumb: scale to zero anything asynchronous, scheduled, or GPU-backed. Keep a warm replica on anything a human is waiting for.

When to choose KEDA

Choose KEDA when:

  • Load comes from a queue or stream. Consumers of Kafka, RabbitMQ, SQS, Service Bus, NATS, or Pub/Sub scale best on queue depth or consumer lag, not CPU. A backlog should add pods immediately, even if CPU has not spiked yet. KEDA reads the source directly and scales accordingly.
  • You want scale-to-zero. Batch processors, infrequently used internal tools, and event-driven microservices can sit at zero pods when idle and activate on the first message. On clusters where capacity is paid for, this is a direct cost saving - especially combined with node autoscaling.
  • You scale on schedules. The cron scaler pre-warms capacity before known peaks (market open, business hours) and scales down afterward, without custom controllers.
  • You need custom metrics without the adapter tax. Rather than building and operating a Prometheus Adapter to expose a metric to HPA, KEDA’s Prometheus and vendor scalers consume those signals directly.

For UAE AI/ML and data teams, KEDA shines on inference queues and batch pipelines where scale-to-zero between bursts meaningfully cuts GPU and compute spend. Pair pod-level KEDA with node-level provisioning - see our companion guide on Karpenter vs Cluster Autoscaler - so that scaling pods to zero also lets idle nodes drain away.

When to choose HPA

Choose plain HPA when:

  • Load correlates with CPU or memory. Classic web and API workloads scale well on resource utilization. HPA handles this with no extra components - it is already in your cluster.
  • You do not need scale-to-zero. If a baseline of at least one replica is always acceptable (or desirable for latency), HPA’s one-replica minimum is fine, and you avoid the cold-start latency that scale-to-zero introduces on the first request.
  • You want the smallest possible operational surface. No operator to install, patch, or reason about during incidents. For risk-averse or tightly governed platforms, fewer moving parts is a feature.
  • Your custom metric is simple and already exposed. If you have one straightforward custom metric and an adapter already running, HPA can use it directly without adopting KEDA.

A steady-traffic UAE banking portal with predictable diurnal load is often best served by HPA on CPU plus a sensible minimum replica count - simple, well understood, and easy to audit.

Can you use them together?

In practice, using KEDA is using HPA together - every ScaledObject is backed by an HPA that KEDA creates and manages. So the question is really about avoiding conflict.

The rule: never point a manually created HPA and a KEDA ScaledObject at the same Deployment. Both would try to set the replica count and fight each other. Keep one controller per workload:

  • Use plain HPA directly for simple CPU / memory workloads.
  • Use KEDA (which owns its HPA) for event-driven or scale-to-zero workloads.

A common real-world split is HPA for request-driven frontends and KEDA for the queue consumers and batch jobs behind them - different workloads, different controllers, no overlap. And remember that pod autoscaling only frees real capacity if node autoscaling reclaims the emptied nodes, which is why teams tune KEDA / HPA alongside a node autoscaler rather than in isolation.

Go look at the HPA KEDA made for you

This is the fastest way to make the relationship concrete, and a genuinely useful debugging habit. Apply a ScaledObject, then run kubectl get hpa. You will find an HPA named keda-hpa-{scaled-object-name}, owned by KEDA, with an external metric as its target. That metric is served by KEDA’s metrics adapter through the standard Kubernetes external metrics API.

Two things follow from that. First, when scaling misbehaves, kubectl describe hpa keda-hpa-<name> tells you whether the problem is the metric value KEDA is publishing or the scaling decision the HPA is making, which are very different bugs with very different fixes. Second, you have not given up any HPA tuning by adopting KEDA.

You still get full HPA behavior control

A frequent objection is that KEDA hides the HPA and takes the tuning knobs with it. It does not. The ScaledObject exposes them under advanced.horizontalPodAutoscalerConfig:

  • advanced.horizontalPodAutoscalerConfig.behavior passes straight through to the HPA’s scaling behavior, so stabilization windows and scale-up or scale-down policies work exactly as they do on a hand-written HPA. This is where you damp the flapping that queue-driven scaling can cause.
  • advanced.horizontalPodAutoscalerConfig.name overrides the generated HPA name when a naming convention or policy requires it.

So the choice is not “KEDA or HPA tuning”. It is “drive the HPA yourself, or let KEDA drive it while you keep the steering wheel”.

Migrating a workload from HPA to KEDA

Order matters, because the failure mode is silent flapping rather than an error:

  1. Delete the existing HPA first. Do not create the ScaledObject alongside it, even briefly. Two controllers writing the same replica count will fight, and the symptom is a Deployment oscillating for reasons nothing logs clearly.
  2. Create the ScaledObject with minReplicaCount set to your old HPA’s minReplicas. Do not enable scale-to-zero on day one.
  3. Confirm the generated HPA exists and is reporting sensible metric values under load.
  4. Then lower minReplicaCount to 0 once you have watched a full traffic cycle and measured the cold-start cost on a real request.

The split in a real cluster

In practice a healthy cluster runs both controllers side by side across different workloads: plain HPA on the API and web tiers where CPU tracks load, KEDA ScaledObjects on the queue consumers and inference services behind them, and KEDA ScaledJobs on batch work that should scale per unit of work rather than per replica. That is not a compromise architecture, it is the intended one. The only thing to police is the boundary: one controller per Deployment, always.

KEDA and HPA in 2026: versions and compatibility

Autoscaling advice ages badly, so here is the current state of both sides.

KEDA. KEDA is a CNCF graduated project, the foundation’s highest maturity tier. It was accepted into the CNCF in March 2020, reached incubating status in August 2021, and graduated in August 2023. The current line is KEDA 2.20, released in May 2026, with v2.20.1 published in June 2026 and 2.20.2 shipping in the Helm chart in July 2026. The scaler catalogue now stands at 70+ built-in scalers, up from the 60-odd of a couple of years ago, spanning message queues, databases, metrics systems, cloud services, CI/CD runners, and cron.

Notable changes in the 2.20 line if you are upgrading: KEDA now records Kubernetes events through the events.k8s.io API group rather than the legacy core events resource, following a Kubernetes dependency bump. There is a fix for a concurrent map read/write race in the fallback status update that could panic when several triggers scaled at once, which is worth having if you run multi-trigger ScaledObjects. The release also added fallback behavior for scalingModifiers and introduced an Elastic Forecast Scaler.

Kubernetes compatibility. KEDA generally tests each release against at least N-2 Kubernetes minor versions, and the current matrix runs:

KEDA versionTested Kubernetes versions
v2.20v1.33 - v1.35
v2.19v1.32 - v1.34
v2.18v1.31 - v1.33

Check this before an upgrade in either direction. A KEDA version that is two releases behind your cluster is the kind of thing that works fine until a CRD field silently does nothing.

HPA. The comparison point here is stability, and that is the whole argument for it. autoscaling/v2 has been the stable API since Kubernetes 1.23, and it does not churn. There is no operator to upgrade, no compatibility matrix to check against your control plane, and no CRDs to reconcile during a cluster upgrade. For platforms under tight change control, “nothing to version” is a genuine feature, and it is the reason plain HPA remains the right answer for a large share of workloads even in 2026.

How NomadX Kubernetes Delivers

NomadX Kubernetes runs autoscaling and cost optimization as fixed-scope sprints:

  • 5-day Autoscaling Readiness Assessment - reviews current pod and node autoscaling, identifies workloads that should be event-driven or scale-to-zero, and recommends KEDA or HPA per workload
  • 2-3 week Autoscaler Implementation Sprint - deploys and tunes KEDA scalers and HPAs, wires event sources (Kafka, queues, Prometheus, cron), and validates scale-to-zero behavior with safe rollback
  • Monthly Cost Optimization Retainer - ongoing autoscaler tuning, rightsizing, and spend reporting across pod and node layers

Book a free 30-minute discovery call to scope your Kubernetes autoscaling and cost engagement with a NomadX Kubernetes engineer.

Frequently Asked Questions

KEDA vs HPA: which should I use?

Use plain HPA if your workloads scale well on CPU, memory, or a custom metric you already expose, and you do not need scale-to-zero - it is built into Kubernetes with nothing to install. Use KEDA when you need event-driven autoscaling on external sources (Kafka lag, queue depth, SQS messages, Prometheus queries, cron schedules) or scale-to-zero for idle workloads. The key point: KEDA is not a replacement for HPA - it builds on top of HPA, creating and managing an HPA object for you and feeding it external metrics. For most event-driven or bursty workloads in 2026, KEDA is the better fit; for simple CPU / memory scaling, HPA alone is enough.

Does KEDA replace HPA?

No. KEDA extends HPA rather than replacing it. When you create a KEDA ScaledObject, KEDA generates and manages a standard HorizontalPodAutoscaler under the hood and acts as an external metrics adapter that feeds it values from your event source. HPA still does the actual scaling math between its minimum and maximum replicas. KEDA's added value is the scale-to-zero transition (0 to 1 and back) and the 70+ scalers that turn external signals into metrics HPA can consume. Think of KEDA as a superset: everything HPA does, plus event-driven sources and scale-to-zero.

What is scale-to-zero and can HPA do it?

Scale-to-zero means running zero pods when there is no work, then spinning the first pod up the moment work arrives. Plain HPA cannot scale a Deployment below one replica - its minimum is one, and no configuration changes that. KEDA adds true scale-to-zero: its controller polls the event source on pollingInterval (30 seconds by default) and activates the workload from zero to one when there are messages in a queue, lag on a topic, or any other trigger, then hands ongoing scaling back to the HPA it manages. Going the other way, once all triggers have been inactive for cooldownPeriod (300 seconds by default), KEDA patches the replica count to zero directly. The trade-off is cold-start latency on the first request, so scale to zero anything asynchronous, scheduled, or GPU-backed, and keep a warm replica on anything a human is waiting for.

What metrics can HPA scale on?

HPA scales on resource metrics (CPU and memory) out of the box via the metrics server, plus custom metrics and external metrics if you deploy an adapter (such as Prometheus Adapter) that implements the Kubernetes custom / external metrics API. So HPA can technically scale on almost anything, but you have to build and maintain the metrics-adapter plumbing yourself. KEDA bundles that plumbing for 70+ sources, which is why event-driven scaling is far less work with KEDA than wiring custom adapters into raw HPA.

What event sources does KEDA support?

KEDA ships 70+ scalers covering message queues (Kafka, RabbitMQ, AWS SQS, Azure Service Bus, NATS, Google Pub/Sub), databases (PostgreSQL, MySQL, MongoDB, Redis), metrics systems (Prometheus, Datadog, New Relic, Azure Monitor, CloudWatch), cloud storage and serverless triggers, cron schedules, and many more. Each scaler knows how to read a meaningful signal - queue length, consumer lag, query result, schedule - and turn it into a metric that drives autoscaling, including the activation from and to zero.

Can I use KEDA and HPA together?

You already are when you use KEDA - it creates and manages an HPA for each ScaledObject. What you must not do is point a manually created HPA and a KEDA ScaledObject at the same Deployment, because they will both try to set replica counts and conflict. The clean model is: use plain HPA directly for simple CPU / memory workloads, and use KEDA (which owns its HPA) for event-driven or scale-to-zero workloads. One controller per Deployment.

Get Started for Free

We would be happy to speak with you and arrange a free consultation with our Kubernetes Expert in Dubai, UAE. 30-minute call, actionable results in days.

Talk to an Expert