Breaking down scale-to-zero: when scaling replicas to zero is safe and beneficial, when it's dangerous due to cold start, and how to use activationThreshold to prevent flapping.

In episode 4 we got to know minReplicaCount: 0 — the feature that most often draws people to KEDA. Episode 5 dissects it completely: what actually happens when replicas go to zero, why this saves money, but also when this is a bad decision.
Spoiler: scale-to-zero isn't a free feature. It's a trade-off between cost and latency, and this episode gives you a framework for making that decision consciously.
When minReplicaCount: 0 is set and there are no events, KEDA sets the HPA to zero replicas. Pods are deleted, and the Deployment has no pods at all. This is different from shutting down the deployment — the workload stays registered and ready to be "woken up" the moment the metric crosses the threshold.
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-worker-scaledobject
spec:
scaleTargetRef:
name: order-worker
pollingInterval: 30
cooldownPeriod: 300
minReplicaCount: 0
maxReplicaCount: 10
triggers:
- type: rabbitmq
metadata:
queueName: orders
queueLength: "20"kubectl get deploy order-worker
kubectl get hpa order-worker-scaledobject
kubectl get pods -l app=order-workerThe third command will show an empty pod list, while the HPA remains and actively monitors metrics. For workloads idle for hours — night workers, batch reports, infrequent AI inference — this means zero compute cost for idle time, which can translate to 40-60 percent savings on the monthly bill. If you want to see the status detail, read the object directly: kubectl get scaledobject order-worker-scaledobject -o yaml.
Scale-to-zero has a hidden cost: cold start. When the first event arrives, a new pod must be created, the image pulled, and the container started. During that window, messages wait in the queue.
Scale-to-zero is safe if your workload isn't latency-sensitive: batch processing at night, scheduled ETL, data analysis. A minute of waiting for a pod to come up is fine because what matters is that messages eventually get processed.
It's dangerous if the process interacts directly with users or downstream systems waiting for a fast response — for example, workers handling HTTP requests, or consumers that must keep consumer lag below a certain threshold. For these cases, don't use zero:
spec:
scaleTargetRef:
name: web-worker
minReplicaCount: 2
maxReplicaCount: 20
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring:9090
query: sum(rate(worker_processed_total[2m]))
threshold: "10"Warning
Beware of the long-poll pattern: workers that block on a connection waiting for messages (e.g. RabbitMQ consumers) still consume resources while idle. Scale-to-zero does shut those pods down, but make sure the messaging mechanism can hold messages while the pod is dead — otherwise messages may be considered failed.
If scale-to-zero is too aggressive but cost is still a concern, use idleReplicaCount. KEDA scales replicas down to the idle value when there are no events — pods stay alive (ready to wake quickly) but at minimal cost:
spec:
scaleTargetRef:
name: order-worker
minReplicaCount: 0
maxReplicaCount: 10
idleReplicaCount: 1
triggers:
- type: rabbitmq
metadata:
queueName: orders
queueLength: "20"With this configuration, replicas drop to 1 (not 0) when idle — a good trade-off between cost and wake-up speed.
A common problem with minReplicaCount: 0 is flapping: occasional small events cause KEDA to wake a pod that immediately dies again. Every wake-sleep cycle has a cost — pods get pulled, scheduled, and paid for a few seconds.
The solution is activationThreshold. The metric must pass this value before KEDA starts scaling from zero. Example: a RabbitMQ queue with queueLength: 20 and activationThreshold: 10 means KEDA only wakes a pod if there are more than 10 messages waiting — one or two transient messages won't trigger anything.
spec:
triggers:
- type: rabbitmq
metadata:
queueName: orders
queueLength: "20"
activationThreshold: "10"Tip
activationThreshold is different from threshold: threshold determines the target replicas per metric, while activationThreshold determines the on-off point from zero. Tuning both is an art — episode 19 covers advanced tuning.
There are three knobs you can turn to control how "easily" KEDA wakes up:
activationThreshold: how high the metric must be before scaling up from zero.pollingInterval: how often KEDA checks (small = more responsive, large = cheaper on the API).cooldownPeriod: how long to wait before scaling replicas down (large = less flapping, but leaves pods idle longer).Episode 5 makes scale-to-zero usable safely. Here's what you must bring along:
minReplicaCount: 0 saves 40-60 percent of idle compute for batch workloads.idleReplicaCount is the compromise.activationThreshold prevents flapping by delaying scale-up from zero.In episode 6 we'll cover the part that often trips people up once scalers are configured: authentication. TriggerAuthentication and ClusterTriggerAuthentication, from secretTargetRef to podIdentity on AWS, Azure, and GCP.