Published April 26, 2026 · Comparison
KuberNap vs kube-downscaler: schedules vs activity
kube-downscaler scales Kubernetes workloads up and down on annotation-driven time schedules. KuberNap scales them based on observed activity and wakes them on demand via an HTTP API. Both are free and open-source; which one fits depends on whether your team's idle hours are predictable.
Background - kube-downscaler and GoKubeDownscaler
The original hjacobs/kube-downscaler project from Henning Jacobs has been around since roughly 2018. It's a Python controller that reads downscaler/uptime and downscaler/downtime annotations on workloads and scales replica counts based on the configured time windows. The original repository is now archived.
The actively maintained successor is caas-team/GoKubeDownscaler, a Go rewrite under GPL-3.0 licensed by the caas-team at Communardo. GoKubeDownscaler v1.2.1 shipped on March 31, 2025 and the project is actively developed in 2026. The same maintainers also keep py-kube-downscaler - the modernized Python fork - alive for teams that prefer the original runtime.
The kube-downscaler family does what its name says, well. It supports a notably broad set of workload types: Deployments, StatefulSets, CronJobs, HPAs, DaemonSets, Jobs, PodDisruptionBudgets, KEDA ScaledObjects, Argo Rollouts, Zalando Stacks, Prometheus Operator custom resources, and GitHub Actions AutoscalingRunnerSets. That's broader workload coverage than most direct competitors. The Go rewrite added leader election for HA, reverse timespans across midnight, RFC3339 timestamps, error events on workloads, and KEDA auto-exclusion to prevent conflicts when both controllers are installed.
Configuration cascades through four scopes - CLI args, env vars, namespace annotations, workload annotations - with the most specific scope winning. This is powerful for platform teams that want a cluster-wide default with per-namespace or per-workload overrides.
Where KuberNap is different
KuberNap takes a different design assumption: idle is whatever activity says it is, not what the clock says. The schedule is implicit in usage, and wake is a single API call.
Three concrete differences:
- Activity-based detection. KuberNap computes a 0–100 idle score per deployment from CPU usage (40%), recent traffic via pod restart frequency (40%), and pod age (20%). A score at or above 75 marks the deployment as a sleep candidate. kube-downscaler does not consider activity at all - it scales on the schedule regardless of what the workload is doing.
- Wake-on-demand HTTP API. A POST to
/api/v1/namespaces/{ns}/wakerestores all sleeping workloads in a namespace in roughly one second. This is the path for "developer working late," "incident deploy at 2am," or "Slack bot that wakes staging on demand." kube-downscaler has no equivalent - to wake outside the schedule, you edit annotations and wait for the next reconciliation. - Audit trail and event log. Every sleep and wake action is recorded in an in-memory event log exposed at
GET /api/v1/eventswith the actor, target, timestamp, prior state, and new state. The workload itself is also annotated withkubernap.com/slept-atandkubernap.com/original-replicasso the action is self-describing inkubectl describe. kube-downscaler logs to stdout and emits Kubernetes events that evict in a few hours.
When to choose kube-downscaler
- Your team has predictable office-hours patterns and no late-night/weekend work. "Down at 18:00 Friday, up at 08:00 Monday" is the right model.
- You need broader workload type coverage than KuberNap currently provides - DaemonSets, Argo Rollouts, Zalando Stacks, Prometheus Operator CRs, GitHub Actions runner sets.
- You want CLI/env/annotation hierarchical config with cluster-wide defaults and fine-grained overrides per namespace or workload.
- You're already using the kube-downscaler annotation conventions and have institutional memory invested in them.
- You're comfortable owning the Helm deployment, the upgrade path, and the debugging when scaling decisions don't match expectations.
When to choose KuberNap
- Your team works irregular hours - multiple timezones, late deploys, weekend incidents - and a fixed schedule would scale staging down while someone's actually using it.
- You need wake-on-demand: a developer hits an HTTP endpoint and the namespace is back in seconds, no waiting for the next uptime window.
- You want activity-based detection that doesn't require authoring per-namespace or per-workload annotations to express what "idle" means for your team.
- You want an audit trail accessible through an API, not stdout logs or transient Kubernetes events.
- You want state stored entirely in resource annotations, no external database, no CRDs, no webhooks - easy to inspect with
kubectl describe. - You want a permissive license for downstream commercial use - Apache 2.0 vs kube-downscaler's GPL-3.0 makes a difference for some organizations' compliance reviews.
Migration notes
If you're currently running kube-downscaler or GoKubeDownscaler and evaluating KuberNap, the safest path is parallel operation followed by a clean cutover.
- Install KuberNap in a separate namespace (e.g.
kubernap-system) - it doesn't touch existingdownscaler/*annotations and uses its ownkubernap.com/*prefix, so the two tools don't conflict on the same resources. - Configure kube-downscaler to exclude the namespaces KuberNap is managing (or vice-versa). Pick one tool per namespace; running both on the same namespace is unnecessary and confusing.
- Observe both for one or two cycles. KuberNap's
GET /api/v1/eventsshows what KuberNap did; kube-downscaler logs show what it did. Compare. - When confident, expand KuberNap's namespace coverage and uninstall kube-downscaler. There is no annotation rewrite required because KuberNap doesn't read
downscaler/*annotations - the migration is "stop one, start the other."
For teams with deeply embedded downscaler/uptime annotations across many workloads, kube-downscaler may simply be the right long-term answer. The migration cost is real and only worth paying if KuberNap's activity detection or wake-on-demand solves a problem the schedule can't.
Operational considerations
Both tools are operational dependencies once installed. A few practical differences worth thinking through before committing:
- Failure mode. kube-downscaler fails closed: if the controller stops running, no new scaling happens but existing scaled-down workloads stay down until you bring it back. KuberNap fails open in the same scenario: existing sleeping workloads stay sleeping, but you can manually wake them by editing the annotation if KuberNap itself is unavailable.
- Observability surface. kube-downscaler emits Kubernetes events on the workloads it touches and logs to stdout. KuberNap exposes a
/api/v1/eventsHTTP endpoint with the full audit log queryable as JSON. Pick the one that matches your existing monitoring stack - both are scriptable. - Multi-cluster. Neither tool has built-in multi-cluster coordination. If you run 5 clusters, you install 5 instances and manage them independently. For organizations with many clusters, this is the same overhead either way.
Quick reference
| Capability | kube-downscaler | KuberNap |
|---|---|---|
| Scaling trigger | Time schedule (annotations) | Activity (CPU + traffic + age) |
| Wake-on-demand | No - schedule only | Yes - HTTP POST |
| Workload coverage | Deploy, STS, CronJob, HPA, DS, Jobs, PDB, +6 more | Deploy, STS, CronJob |
| Audit trail | Stdout logs + K8s events | In-memory event log via API |
| Annotation prefix | downscaler/* | kubernap.com/* |
| License | GPL-3.0 | Apache 2.0 |
Related reading
- KuberNap vs KEDA scale-to-zero - event-driven vs activity-based scaling.
- How to scale idle Kubernetes namespaces to zero - three approaches compared.
- Kubernetes dev cluster cost cutting: 2026 guide - full cost-cutting playbook.
FAQ
- What is kube-downscaler?
- kube-downscaler is an open-source Kubernetes controller that scales deployments, statefulsets, cronjobs, HPAs, and other workloads up and down based on annotation-driven time schedules. The original Python project from Henning Jacobs is archived; the actively maintained successor is GoKubeDownscaler from caas-team.
- Does kube-downscaler do wake-on-demand?
- No. kube-downscaler is purely schedule-based. If the schedule says 'down between 18:00 and 08:00,' a workload stays down during that window regardless of activity. There is no API call that wakes a workload outside the schedule - you would need to edit the annotation or wait for the next uptime window.
- When should I pick kube-downscaler over KuberNap?
- When 'idle' for your team is fully expressible as a time window. Predictable office-hours-only workflows, no weekend or night work, no on-call deploys. kube-downscaler also covers a broader set of workload types (DaemonSets, PDBs, Argo Rollouts, Zalando Stacks) than KuberNap currently does.
- When should I pick KuberNap over kube-downscaler?
- When your team has irregular hours, supports multiple timezones, ships on weekends sometimes, or needs to wake a dev environment instantly during an incident. KuberNap detects idleness from activity signals (CPU, traffic, pod age) and exposes wake as a one-second HTTP call.
- Can I migrate from kube-downscaler to KuberNap?
- Yes. Install KuberNap alongside kube-downscaler in observe-only mode first, compare scaling decisions, then uninstall kube-downscaler when confident. KuberNap stores its state in distinct kubernap.com/* annotations, so the two tools do not conflict on the same resources.