Kubernetes v1.37 Turns HPA Scale-to-Zero Into a Default, Not an Add-On
Kubernetes v1.37 graduates native HorizontalPodAutoscaler scale-to-zero support to Beta and turns it on by default, closing a gap KEDA has worked around for years.
A queue worker that costs nothing while the queue is empty sounds like an obvious feature for a system built around elastic scaling. For most of Kubernetes’ history, it was not one. Kubernetes v1.37, released August 26, 2026 under the codename Garhwal, graduates HorizontalPodAutoscaler (HPA) support for scaling a workload all the way to zero replicas to Beta, and the feature is enabled by default. A workload built on expensive, dedicated hardware like GPUs can now disappear entirely when nothing is waiting for it, then reappear the moment work shows up again, without a separate autoscaler and without flipping on an Alpha-only setting almost no production cluster ever touched.
Table Of Content
The feature traces back to KEP-2021, first implemented in Kubernetes 1.16 in 2019 and left in Alpha for nearly seven years while the underlying condition-tracking logic matured. Kubernetes 1.37 release lead Dipesh Rawat put the payoff in plain terms in comments picked up by Network World: “if you are running some high processing workloads on expensive GPUs, it’s going to save you some costs.” The Kubernetes Blog’s own announcement, written by Johannes Würbach, frames it the same way: “The savings are largest when each Pod reserves expensive resources, including dedicated CPUs or GPUs.”
Why CPU and Memory Metrics Can’t Reach Zero
The HPA has always been able to scale a Deployment down toward a floor set by minReplicas, but that floor could never legally be zero for the metrics most clusters actually use. The Kubernetes Blog post explains the mechanical reason plainly: “The HPA commonly scales on CPU or memory usage. Both metrics come from running Pods. Once the replica count reaches zero, there are no Pods left to measure and no signal that can tell the HPA to scale back up.” A metric that only exists because a Pod is running cannot also be the signal that tells Kubernetes to start one. KEP-2021 states the same constraint directly: “Since CPU and memory utilization can only be measured on running pods, scaling to zero will be limited to object and external metrics.”
What Object and External Metrics Change
Object metrics (tied to a specific Kubernetes object) and external metrics (pulled from a system outside the cluster, most often through an adapter like prometheus-adapter) don’t have that problem. As the Kubernetes Blog post puts it: “A queue length, for example, exists independently of the workers that consume it. The HPA can continue reading the queue length while no workers are running.” The queue is the thing being measured, not the Pods reading from it, so the signal survives even after the last worker exits.
A minimal HorizontalPodAutoscaler that takes advantage of this looks like the following. This is an illustrative manifest built around the same queue_consumer_lag metric name used in the Kubernetes Blog’s own Prometheus-adapter example, not a copy-paste from the post itself:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-queue-worker
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-queue-worker
minReplicas: 0
maxReplicas: 20
metrics:
- type: External
external:
metric:
name: queue_consumer_lag
selector:
matchLabels:
queue: orders
target:
type: AverageValue
averageValue: "10"
Two things have to be true before a manifest like this will work. First, the cluster needs a working External Metrics API, since the API server has nothing to poll otherwise; kubectl get --raw '/apis/external.metrics.k8s.io/v1beta1', the exact verification command the Kubernetes Blog post shows, confirms whether one is registered. Second, autoscaling/v2 is required, since the original autoscaling/v1 API only understands CPU utilization and has no concept of object or external metric sources at all.
What Actually Changed in v1.37
Turning the Feature Gate On
The official Kubernetes documentation is specific about where the switch lives: “Setting minReplicas: 0 requires at least one object or external metric to be configured; the API server rejects the HorizontalPodAutoscaler otherwise. This behavior is controlled by the HPAScaleToZero feature gate, which is enabled by default. The feature gate must be enabled on both the kube-apiserver (which allows minReplicas: 0) and the kube-controller-manager (which performs the scaling).” Both halves matter: the API server validates that the manifest is even legal to submit, and the controller manager is the process that actually walks a workload down to and back up from zero.
The ScaledToZero Condition
Kubernetes still needs a way to tell a workload the HPA deliberately parked at zero apart from one someone paused by hand. v1.37 adds a status condition for exactly that. Per the official docs: “While the HPA is holding a workload at zero replicas, it records a ScaledToZero condition set to True on the HorizontalPodAutoscaler’s status. The HPA uses this condition to distinguish a workload that it scaled to zero (and will scale back up when the metric returns) from one that was manually deactivated by setting its replica count to 0. Once the workload is scaled back up, the condition is set to False with the reason NotScaledToZero.” Anyone debugging why a Deployment sits at zero replicas can now check one field instead of guessing.
Why KEDA Has Handled This Itself for Years
sxz.io covered KEDA’s approach to queue-depth autoscaling last month, and KEDA’s own architecture is a good illustration of exactly the gap v1.37 closes. KEDA’s documentation describes two separate phases most users never think about: an “activating (or deactivating) phase,” where, in KEDA’s own words, “KEDA (operator) has to decide if the workload should be scaled from/to zero,” and a distinct “scaling phase,” where “it is the HPA controller who takes the scaling decisions” once at least one replica is running.
That split exists because, for most of Kubernetes’ life, the HPA itself could not be trusted with the zero-to-one decision on its own: minReplicas: 0 required the same HPAScaleToZero gate that had sat in Alpha since Kubernetes 1.16, a setting almost no production cluster enabled. KEDA built its own activation logic around that gap rather than wait for it to close. None of this makes KEDA redundant now that the gate is Beta and on by default. KEDA still supplies dozens of ready-made scalers, from SQS and Kafka to cron schedules and Prometheus, so teams don’t have to run their own custom or external metrics adapter for every backend. What changes is narrower but real: the specific mechanism KEDA’s activation phase exists to work around is now a supported, documented, default part of core Kubernetes.
The Trade-offs Nobody Should Skip
Scaling to zero is not free, and the Kubernetes Blog post is direct about where it costs something. On cold start: “The HPA must observe the metric, schedule a Pod, and start the application. This works well when work can wait in a durable queue.” A batch job or queue consumer can tolerate that startup delay because the work is sitting in a durable queue the whole time. A synchronous, request-driven service cannot assume the same thing, which the post also calls out explicitly: “Kubernetes Services do not buffer requests while no Pods are ready, so HTTP and other request-driven workloads need a separate buffering layer.” A Kubernetes Service has no concept of holding a request until a Pod exists to receive it; if the last Pod behind a Service exits and a request arrives before a new one is ready, that request has nowhere to go unless something else, a queue, a proxy with its own buffering, or a serverless-style gateway, is standing in front of it.
The Road to GA
KEP-2021 lays out concrete graduation criteria rather than a vague promise of a future release. Reaching Beta required, among other items, that the “condition-based scale from/to zero implementation” be merged, that unit and integration tests cover the feature gate both enabled and disabled, including “a negative case ensuring HPAs configured with resource (CPU) metrics are not scaled to zero,” and that a “production readiness review” be “approved for beta,” all bars v1.37 clears. Graduating from Beta to GA requires the gate to have been “enabled by default in beta for at least one release without blocking bugs,” with beta-user feedback gathered and addressed and e2e tests “running consistently without flakes.” In practice, that means GA is realistically a v1.38-or-later prospect, and only if the newly default-on behavior in v1.37 doesn’t surface problems serious enough to block it once real clusters start using it at scale.
For teams already running queue-driven or GPU-bound batch workloads on Kubernetes, the practical takeaway is that the pattern KEDA and similar tools have long offered as an add-on is now something the HPA can do on its own, provided the workload is tolerant of cold starts and already exposes a metric through the object or external metrics API. For everything else, particularly anything answering live HTTP traffic, the trade-offs the Kubernetes Blog post describes are the reason this shipped as Beta and not GA.








No Comment! Be the first one.