Kubernetes 1.37 "Garhwal" shipped on August 26, 2026 with 67 enhancements, and one quiet graduation matters more to your idle-bill than all the AI-scheduling headlines: HPAScaleToZero (KEP-2021) moved from alpha to beta, enabled by default. Set minReplicas: 0 on an HPA and your workload can now idle to zero pods and wake back up with no feature gate and no add-on installed.
So here is the verdict up front: for HTTP workloads already sitting behind Prometheus or ingress-request metrics, you can now delete KEDA's HTTP add-on and pocket roughly two-thirds of your idle node footprint — about €32/month per 20 idle preview apps on current Hetzner pricing in the worked example below. But "no gate, no KEDA" is not "no work": CPU and memory metrics cannot wake a workload that has zero pods, so you still need an external signal that exists independently of your pods, plus something that holds requests during the cold start. And if you scale on anything that is not HTTP — queues, streams, cron-like events — KEDA is untouched by this graduation and stays.
Read on for the mechanics, the two hard requirements with a concrete YAML sketch, the full before/after math with a KEDA baseline row, and the decision table.
What 1.37 actually changed
Since Kubernetes 1.16, the HPA controller has contained a small conditional: allow minReplicas: 0 when the HPAScaleToZero feature gate is on. For a decade it sat in alpha, off by default — not because it was unstable, but largely through KEP-process inertia. The promotion commit landed June 11, 2026, graduating the gate to beta and flipping the default to true for v1.37. Homelab operators noticed within days of the release: clusters on 1.37 could drop their explicit HPAScaleToZero=true controller-manager flags, confirmed against upstream's own versioned feature list.
Three mechanics matter:
spec.minReplicas: 0is now accepted by default. The API validation forMinReplicasmoved to the declarative validation framework and dynamically respects the gate — on 1.37+ servers it just passes.- It works only with object and external metrics. This is the load-bearing constraint. A Deployment with zero pods produces no CPU or memory utilization numbers, so there is nothing for the HPA controller to observe and no value that can cross a threshold to wake the workload back up. The signal must live outside the pods: requests-per-second from the ingress, queue depth from a broker, a Prometheus query — anything queryable while replica count is zero.
- A new HPA status condition tracks the zero state, so
kubectl describe hpatells you the scaler deliberately parked the workload rather than failing to compute replicas.
One caution for mixed fleets: the gate is enforced server-side by the kube-controller-manager. During a rolling control-plane upgrade where an older controller-manager is still leader, minReplicas: 0 behavior follows whichever controller is actually running — verify the gate state on the serving version (more on this in the guardrails).
The two things "just works" still needs
Dropping to zero is the easy direction — the metric falls to nothing and replicas follow. Waking up is where teams get bitten. You need exactly two things, and both must exist before you set minReplicas: 0:
1. An external signal that survives zero. CPU/memory are out, as above. In practice this means a Prometheus Adapter query (e.g. per-service HTTP requests per second), an ingress controller's request metric exposed as an external metric, or a queue-length metric. A minimal sketch:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: preview-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: preview-app
minReplicas: 0
maxReplicas: 5
metrics:
- type: External
external:
metric:
name: http_requests_per_second
selector:
matchLabels:
service: preview-app
target:
type: AverageValue
averageValue: 10
behavior:
scaleDown:
stabilizationWindowSeconds: 300Note the stabilizationWindowSeconds: without a generous scale-down window, a workload flaps between zero and one on every stray health check or scraper hit. Five minutes of quiet before parking is a sane default for preview environments.
2. Something that buffers requests during the cold start. When the first real request arrives at zero replicas, some component must hold the connection open while pods start — otherwise the request 502s and your "scale to zero" reads as an outage. Knative solved this years ago with its activator, which intercepts traffic, buffers it, and forwards once pods are ready; KEDA's HTTP add-on runs the same pattern with its interceptor proxy. Native HPA gives you the scaling decision but no buffering component — you must supply one (an ingress with retry-on-503 and a queue, a Knative-style activator, or the KEDA HTTP add-on's interceptor kept purely as a buffer). Measure your own cold start — community comparisons put Knative-style wakeups around 3 seconds for typical images — and confirm it fits the workload's SLO before parking anything latency-sensitive.
The worked math: what zero actually saves on owned metal
Assumptions, stated plainly so you can substitute your own: a fleet of 20 preview/staging apps, each with requests of 500m CPU / 1Gi RAM, idle roughly overnight and between reviews. Node SKU: Hetzner CX43 (8 shared vCPU, 16 GB RAM, €15.99/month, post-June-2026 pricing). Bin-packing at ~80% allocatable gives roughly 6.4 vCPU / 12.8 Gi usable per node.
| Setup | Reserved footprint | Nodes (bin-packed) | €/month |
|---|---|---|---|
| Before: every app min 1 replica | 20 × 500m / 1Gi = 10 vCPU / 20 Gi | 2 nodes | €31.98 |
| Native HPA to zero (1.37) | Activator + Prometheus Adapter ≈ 1 vCPU / 1 Gi always on | 1 node (shared with other always-on infra) | ~€10–16 |
| KEDA HTTP add-on baseline | KEDA operator + interceptor ≈ 1 vCPU / 1 Gi always on | 1 node | ~€10–16 |
Net savings for this fleet shape: about one full node, ~€16/month — roughly half the idle footprint, once you subtract the always-on overhead both approaches carry. The honest headline: native HPA and KEDA cost nearly the same to run; the win is deleting KEDA's CRDs, upgrade cycle, and second autoscaling control loop from your operations, not deleting its CPU requests.
Sensitivity — because one point flatters:
- 25% of apps latency-critical (kept at min 1): 5 apps always resident ≈ 2.5 vCPU / 5 Gi, plus overhead — still fits one node with room. Savings hold.
- 50% latency-critical: ~5 vCPU / 10 Gi resident — a second node stays. Savings roughly halve.
- Above ~50 idle apps: the freed capacity compounds to two or more nodes, and the savings start paying for real hardware instead of rounding error.
- Wake SLO under ~1s: neither native HPA nor KEDA HTTP is suitable; keep min 1 and stop reading — the cold start dominates everything else.
The pattern this exposes: scale-to-zero pays on flat-rate metal exactly in proportion to your idle share. Metered clouds save per-second; owned boxes save per-node-freed. Small fleets should expect tens of euros per month and a simpler stack — worth doing, not worth a re-architecture.
So do you still need KEDA?
| Workload | Native HPA (1.37+) | KEDA ScaledObject | KEDA HTTP add-on | Knative KPA |
|---|---|---|---|---|
| HTTP idling to zero, Prometheus/ingress metrics present | Best fit — no add-on | Works, extra moving parts | Works, but now redundant with native + a buffer | Works, heaviest option |
| HTTP with no external metric pipeline | Blocked until you build one | Best fit (its own metrics path) | Viable via interceptor metrics | Viable |
| Queue / stream / event-driven (Kafka, RabbitMQ, SQS, cron) | Not supported | Best fit — 50+ scalers, IsActive activation handles 0↔1 | N/A | N/A |
| Need request buffering on wake | Bring your own | Bring your own | Built in (interceptor) | Built in (activator) |
| Ops cost | Zero new components | Operator + CRDs + per-trigger config | Operator + interceptor + CRDs | Full Serving stack |
The rule of thumb: if your wake signal is HTTP and you already run the metrics pipeline, graduate to native HPA and retire the HTTP add-on. If your wake signal is anything else, KEDA is still the answer — this beta changes nothing about event-driven scaling, and KEDA's activation phase (its explicit 0↔1 logic per scaler) remains the most mature implementation of exactly that transition.
Four guardrails before you set minReplicas: 0
- Verify the serving version first:
kubectl -n kube-system get pods -l component=kube-controller-manager -o yaml | grep -i hpa-scaleshould show nothing forced off, and every control-plane node must run 1.37+. During mixed-version upgrades the oldest controller-manager behavior wins. - Never roll
minReplicas: 0fleet-wide in one change. Start with preview/staging namespaces, watch wake latency for a week, then expand. The blast radius of a missing metric pipeline is every workload silently parked with no way to wake. - Pair every zero-scaled HPA with its wake metric and buffer explicitly. An HPA with
minReplicas: 0on CPU metrics is a workload that parks on first idle and never wakes — lint fortype: Resourcecombined withminReplicas: 0in CI. - Alert on zero-duration, not just replica count. A workload parked for its normal 12 idle hours is savings; one parked for 72 hours straight may be a broken wake signal. Alert when time-at-zero exceeds the workload's known idle pattern.
The boring release that pays
Kubernetes 1.37 is being called a deliberately boring release — incremental graduations, no concepts to re-architect around — and HPA scale-to-zero is the best example of why boring is good. A decade-old alpha conditional, flipped on by default, quietly deletes an add-on from thousands of clusters and halves the idle footprint of every preview environment it touches. No migration project, no new CRDs: upgrade the control plane, add an external metric, keep a buffer in front, and collect the node back.
Running preview environments on machines you own? Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on your own hardware, with per-app autoscaling that respects min/max replicas you declare. Star the repo on GitHub.
Sources
- Kubernetes v1.37 "Garhwal" release announcement (August 26, 2026) — 67 enhancements, 16 stable / 23 beta / 27 alpha: kubernetes.io/blog/2026/08/26/kubernetes-v1-37-release
- HPAScaleToZero promotion to beta commit (June 11, 2026): kubernetes/kubernetes
- KEP-2021: support scaling HPA to/from zero for object/external metrics: kubernetes/enhancements#2022
- HPA scale-to-zero without KEDA, external-metrics requirement: dev.to/kraszdan
- KEDA HTTP add-on architecture (operator, interceptor, external scaler): keda.sh via Google Cloud docs
- Scale to zero on GKE with KEDA: Google Cloud Blog
- Knative activator request buffering and KPA vs HPA scale-to-zero: Knative serving docs
- Hetzner post-June-2026 pricing (CX23 €5.49/mo, CAX11 €5.99/mo, CPX/CCX ~2–3x hikes): Hetzner 2026 price-adjustment benchmarks



