A dormant tenant app, held open at a minimum of one running replica because that's what the platform's default minReplicas says, costs real money whether or not a single request arrives. On Railway's metered pricing — roughly $0.028 per vCPU-hour and $0.014 per GB-hour — a 1 vCPU / 1 GB container running 24/7 comes to about $30 a month. Render's always-on Starter plan fixes that same idle tenant at $7/mo per service, no traffic required. Multiply either number across a fleet of preview environments, staging apps, and low-traffic side projects, and a self-hosted PaaS is billing — or eating — a tax on doing nothing.
KEDA, the CNCF-graduated Kubernetes Event-Driven Autoscaler, is built specifically to remove that floor: it can take a Deployment to true zero replicas and bring it back from a queue-depth signal, an HTTP request, or any of 60+ other event sources, handing control back to standard HPA the moment there's a real replica running. Here's exactly what that buys a git-push PaaS built on Cluster API, what it costs in cold-start seconds, and where it isn't worth doing at all.
Why Plain HPA Can't Do This
Kubernetes' built-in Horizontal Pod Autoscaler has a hard floor: minReplicas cannot be set to 0. HPA scales a Deployment up and down between a minimum and maximum based on CPU/memory or custom metrics, but that minimum is always at least 1 — there is no "0" state in HPA's model, because HPA has no concept of waking a Deployment back up. If nothing is running, there's no metric to scale from.
KEDA doesn't replace HPA — it wraps it. Under the hood, a ScaledObject generates and manages an HPA resource for the 1-and-above range exactly like today; KEDA only owns the one edge HPA structurally can't cross, the 0↔1 transition. Below 1 replica, KEDA polls the configured event source (a queue depth, a cron schedule, an HTTP request count) and decides when to create the first pod. Above 1, it steps back and lets standard HPA metrics-driven scaling run the rest, unmodified.
That division of labor is why KEDA graduated the CNCF in August 2023 without trying to reinvent autoscaling: it's a single-purpose addition to the existing HPA, not a replacement for it. It ships 60+ built-in scalers (Kafka, RabbitMQ, Prometheus, cron, Redis, SQS, and dozens more) and 9+ authentication providers, and runs in production at organizations including FedEx, Grafana Labs, KPMG, Reddit, and Xbox.
How a Held Request Survives the Trip to Zero and Back
For a git-push PaaS, most tenant apps aren't consuming a Kafka queue — they're serving HTTP. That's what the KEDA HTTP Add-on exists for, and its request-hold mechanic is the part that makes scale-to-zero safe to expose to tenants who never touch a ScaledObject YAML file.
The add-on deploys three components:
- Interceptor — a reverse proxy sitting in front of every scaled tenant app, tracking request concurrency
- Scaler — aggregates the interceptor's metrics and reports them to KEDA as an external metric
- Operator — manages the
HTTPScaledObjectlifecycle per tenant
When a request lands on a backend that's currently at zero replicas, the interceptor doesn't 502 — it holds the request in memory while the scaler reports activity and KEDA scales the Deployment from 0 to 1. Once the first pod passes its readiness probe, the interceptor releases the held request to it. No request is dropped during the gap; it's just delayed by however long the cold start takes.
The Cold-Start Numbers, Concretely
That delay is the actual tradeoff the title promises, and it's measurable. Real-world cold starts typically add 2–5 seconds on top of normal request latency for a small, pre-pulled image with light init logic, climbing past 15 seconds for larger images or heavier startup routines (dependency loading, migrations, JIT warmup).
Benchmarked against Kubernetes 1.36's native HPA on a comparable 0→1 activation path, KEDA completes the scale-up in roughly 18 seconds versus about 32 seconds, and scales a Deployment back down to zero in roughly 70 seconds of stabilization versus about 130 seconds for native HPA settling behavior. KEDA is faster in both directions, but "faster" here still means tens of seconds, not milliseconds — that's the number a platform operator needs before deciding what gets this treatment.
The Dollar Math, and Where It Stops Being Worth It
Put the two numbers together and the tradeoff is concrete: a low-traffic tenant — a marketing site, a staging environment, a webhook receiver that fires a few times an hour — sitting idle 20 of 24 hours a day and switched from always-on-1-replica to KEDA scale-to-zero drops its compute bill by roughly 80–90%, going from Railway's ~$30/month flat idle cost down to compute charged only for the ~4 active hours plus whatever fraction of a minute each cold start adds.
That number isn't universal — it depends entirely on how the tenant's traffic is shaped. Split by workload:
| Workload type | Scale-to-zero fit | Why |
|---|---|---|
| Webhook receivers, cron-triggered jobs, queue consumers | Good | Bursty, tolerant of a multi-second first-request delay, often has no human waiting synchronously |
| Preview environments, staging, side-project demos | Good | Traffic is sparse and unpredictable; nobody's paged if the first load takes 20 extra seconds |
| Internal admin tools, low-QPS dashboards | Conditional | Fine if users tolerate an occasional slow first load; bad if it's someone's daily driver at 9am sharp |
| User-facing APIs with a sub-500ms SLA | Bad | A 15–30 second cold start blows through any latency budget; keep minReplicas: 1 |
The honest version of this recommendation is: scale-to-zero belongs on a per-tenant opt-in, not a fleet-wide default. A platform that force-enables it everywhere trades a predictable idle-cost tax for an unpredictable latency tax on exactly the tenants who can least afford it.
What Changes in a Cluster API Fleet's Scheduler
None of this requires touching the scheduler that Cluster API already owns. Concretely, wiring KEDA into a Cluster API–provisioned, namespace-per-tenant fleet means:
- KEDA's core components deploy once, cluster-wide — not per tenant. The default Helm chart requests 100m CPU / 100Mi memory each for the operator and metrics-apiserver, and 50m CPU / 50Mi memory for the admission webhook — roughly a quarter of a CPU core and a quarter gigabyte of RAM, total, shared across the entire fleet. That fixed cost amortizes toward zero per tenant as the fleet grows; it's nothing close to the per-tenant $30/month this is meant to eliminate.
- An
HTTPScaledObjectgets generated per tenant App CR at deploy time — the same moment the platform already writes a Deployment and Service for a pushed repo, one more CRD gets templated alongside them, scoped to that tenant's existing namespace. - The interceptor sits in the existing ingress path, not in place of it — namespace-scoped NetworkPolicies and RBAC that already isolate tenants from each other don't need to change, because KEDA operates at the Deployment/namespace scope the platform's isolation model already assumes.
- The scheduler itself is untouched. KEDA's entire contribution is the 0↔1 edge; once a pod exists, Cluster API's node provisioning and the standard Kubernetes scheduler place it exactly as they do today. This is additive plumbing, not a scheduler rewrite.
The interceptor is also the one piece worth watching in production rather than trusting blindly — it's a relatively young component compared to KEDA's core scaler, and it's the single point every request for a scaled-to-zero tenant now passes through. Treat it the same as any other piece of shared ingress infrastructure: monitor it, and don't force every tenant behind it on day one.
The Actual Tradeoff
KEDA doesn't make idle compute free — it makes idle compute optional, with a cold-start bill attached instead of a monthly one. For the class of tenant that's idle most of the day and doesn't have a human staring at a loading spinner, that's a straightforward win: a fixed, fleet-wide ~250m CPU of overhead buys an 80–90% compute reduction on every tenant opted in. For a latency-sensitive API, it's the wrong default, full stop. The right shape for a self-hosted PaaS isn't "scale everything to zero" or "never scale to zero" — it's exposing scale-to-zero as a per-app setting and letting the tenant, who actually knows their own latency budget, make the call.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.
Sources
- KEDA official site.
- CNCF: Cloud Native Computing Foundation Announces Graduation of Kubernetes Autoscaler KEDA.
- KEDA HTTP Add-on (GitHub).
- KEDA HTTP Add-on scaling concepts.
- KEDA vs Kubernetes 1.36 Native HPA: The Ultimate Scale-to-Zero Showdown.
- Railway vs Render: Pricing, Reliability & the 2026 Verdict.
- Render vs Railway 2026 - Pricing, DX & When to Use Each.
- KEDA Helm chart values.yaml (GitHub).



