kube-state-metrics and Metrics Server are the two components people confuse most often in Kubernetes observability — both sit near the API server, both expose metrics, and both are frequently installed together. But they answer completely different questions: Metrics Server answers "how much CPU/memory is this Pod using right now?" while kube-state-metrics answers "what is the state of this object — how many replicas does it want, how many does it have, what phase is it in?"
Definitions, Side by Side
| kube-state-metrics | Metrics Server | |
|---|---|---|
| Answers | What state is this object in? | How many resources is this Pod/Node using right now? |
| Data source | Kubernetes API server object watches | kubelet /stats/summary (via cAdvisor) |
| API exposed | Prometheus text format on /metrics | metrics.k8s.io aggregated API |
| Storage | None — a snapshot regenerated on every scrape | Latest sample only, held in memory (~1–2 min TTL) |
| Powers | Prometheus dashboards, alerting, SLOs | kubectl top, HPA, VPA |
| Historical data | Yes, once scraped into Prometheus | No — by design |
| Example metrics | kube_deployment_status_replicas_available, kube_pod_status_phase | container_cpu_usage_seconds_total-derived usage, node.cpu.usage |
Sample Output From Each
kube-state-metrics exposes plain Prometheus text metrics for object state:
kube_deployment_status_replicas_available{deployment="checkout",namespace="prod"} 3
kube_deployment_spec_replicas{deployment="checkout",namespace="prod"} 4
kube_pod_status_phase{pod="checkout-7f9c-abc12",namespace="prod",phase="Running"} 1 Metrics Server exposes live resource usage through the Kubernetes API — you don't scrape it with Prometheus directly, you query it with kubectl top or let the HPA controller read it:
$ kubectl top pod checkout-7f9c-abc12 -n prod
NAME CPU(cores) MEMORY(bytes)
checkout-7f9c-abc12 42m 186Mi Where kubectl top and Kubelet Metrics Fit In
A common source of confusion: kubectl top and "kubelet metrics" are not the same thing as kube-state-metrics, and searching for "kubelet metrics" or "kubectl metrics" usually means you actually want Metrics Server, not KSM.
- kubectl top is a client command. It calls the
metrics.k8s.ioAPI, which is served by Metrics Server — not by kube-state-metrics. If Metrics Server isn't installed,kubectl topreturnserror: Metrics API not available. - Kubelet metrics usually refers to one of two things: (1) the kubelet's own
/metricsand/metrics/cadvisorendpoints, which expose low-level container resource usage that Metrics Server aggregates, or (2) the kubelet's internal Prometheus metrics about its own process health (kubelet_running_pods, etc.). Neither overlaps with what kube-state-metrics reports. - kube-state-metrics never talks to the kubelet at all — it only talks to the API server, which is why it can run as a single central deployment rather than one instance per node.
Decision Matrix: Which One Do You Need?
| Use case | Use |
|---|---|
| Horizontal Pod Autoscaler (CPU/memory-based) | Metrics Server |
kubectl top node / kubectl top pod | Metrics Server |
| Alert when Deployment has fewer available replicas than desired | kube-state-metrics |
| Dashboard of Pod restart counts over the last 30 days | kube-state-metrics (Prometheus stores the history) |
Alert on Node NotReady condition | kube-state-metrics |
| Custom HPA on a business metric (e.g. queue depth) | Neither — use the Prometheus Adapter or KEDA, fed by your own exporter |
| Real-time CPU/memory usage per container | Metrics Server (or cAdvisor/Node Exporter for more granularity) |
In practice, almost every production cluster runs both, since they don't compete for resources or conflict — Metrics Server is typically pre-installed by managed Kubernetes providers (EKS, GKE, AKS) for autoscaling, while kube-state-metrics is added on top for Prometheus-based monitoring. See the Helm installation guide to add kube-state-metrics alongside an existing Metrics Server deployment.
FAQ
Can kube-state-metrics replace Metrics Server?
No. The HPA and kubectl top both read from the metrics.k8s.io API, which only Metrics Server implements. kube-state-metrics doesn't serve that API and can't power autoscaling by itself.
Can Metrics Server replace kube-state-metrics?
No. Metrics Server discards history and has no concept of Deployment replica counts, Pod phase, Node conditions, or any other object-state field — it only knows current CPU/memory usage.
Does kube-state-metrics support autoscaling?
Indirectly — KSM exposes kube_horizontalpodautoscaler_* metrics so you can monitor and alert on HPA behavior in Prometheus, but the HPA controller itself still relies on Metrics Server (or the Prometheus Adapter for custom metrics) to make scaling decisions.