A Kubernetes resource quota is a namespace-level cap on how much a team can consume: total CPU and memory, storage claims, and the number of objects such as Pods and Services. You create it with a ResourceQuota object, pair it with a LimitRange so pods get sensible defaults, and check usage with kubectl describe quota. This guide covers what quotas can limit, how they differ from LimitRange, how scopes work, the behaviors that surprise people in production, and how to keep an eye on quotas when you run more than one cluster.
TL;DR
- A
ResourceQuotalimits the aggregate consumption of a namespace. ALimitRangeconstrains individual pods and containers and can supply defaults. - Once a quota covers CPU or memory, every new pod must declare requests or limits, or the API server rejects it. A LimitRange with defaults fixes that.
- Quotas are absolute numbers. They do not grow when you add nodes, and they do not evict workloads that already exist.
- Scopes let you apply different quotas to different kinds of pods, for example by priority class or Quality of Service.
- Review quotas per namespace and per cluster on a schedule, not only when a deployment fails.
Table of Contents
- Why quotas exist
- What a ResourceQuota can limit
- LimitRange vs ResourceQuota
- The rule that breaks deployments: requests are mandatory
- Using scopes to treat workloads differently
- Behaviors that catch administrators off guard
- How to choose the numbers
- Managing quotas across namespaces and clusters
- Our perspective
- FAQ
- Sources
Why quotas exist
When several teams share a cluster with a fixed number of nodes, one team can easily take more than its fair share. The Kubernetes documentation describes resource quotas as the administrator's tool for exactly this concern.
The failure it prevents is familiar. A memory leak, a runaway CronJob or a deployment scaled to 200 replicas by mistake consumes node capacity, and unrelated teams start seeing pending pods or evictions. A Microsoft workshop on Kubernetes resource management frames quotas and limit ranges together as the foundation of multitenancy, and that matches what most platform teams find in practice: without them, one bad deployment becomes everybody's incident.
A quota is not a scheduler feature. It is enforced at admission: when someone creates or updates an object, the API server checks the request against the namespace's quota and refuses it if it would push usage over a hard limit.
What a ResourceQuota can limit
Quotas cover three families of things, according to the Kubernetes documentation:
- Compute resources: CPU and memory requests and limits, plus hugepages.
- Storage: total requested storage and the number of PersistentVolumeClaims. You can go further and set limits per storage class, which the storage consumption guide walks through.
- Object counts: the number of Pods, Services, Secrets, ConfigMaps and other core API objects.
Here is a minimal quota for a team namespace:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
persistentvolumeclaims: "10"
pods: "50"
services: "10"
Apply it with kubectl apply -f quota.yaml, then read it back:
kubectl describe quota team-a-quota -n team-a
The output lists each resource with its Used and Hard columns, which is the quickest way to see how close a namespace is to its ceiling. The full field list is in the ResourceQuota API reference.
LimitRange vs ResourceQuota
This is the question readers ask most, and the answer is about level of enforcement. A ResourceQuota works on the namespace as a whole. A LimitRange works on each pod or container. The Stack Overflow answer on this exact question puts it plainly: a pod outside the LimitRange constraints is rejected, while a quota applies to all objects in aggregate.
| ResourceQuota | LimitRange | |
|---|---|---|
| Scope | Whole namespace (aggregate) | Each pod or container (and PVCs) |
| Main purpose | Cap total consumption and object counts | Set min, max and default values per object |
| Supplies defaults | No | Yes, default requests and limits |
| Rejects when | Total would exceed the hard limit | A single object falls outside the allowed range |
| Typical owner | Platform or cluster admin | Platform or cluster admin |
The LimitRange documentation notes that by default containers run with unbounded compute resources. A LimitRange can set minimum and maximum values per object and can enforce a ratio between requests and limits.
The two objects are meant to be used together. A common pattern is a LimitRange that gives every container default requests and limits, and a ResourceQuota that caps the namespace total.

apiVersion: v1
kind: LimitRange
metadata:
name: team-a-defaults
namespace: team-a
spec:
limits:
- type: Container
defaultRequest:
cpu: 250m
memory: 256Mi
default:
cpu: 500m
memory: 512Mi
max:
cpu: "2"
memory: 4Gi
With this in place, a developer who forgets to set resources still gets a working pod, and nobody can create a single container larger than 2 CPUs or 4Gi of memory.
The rule that breaks deployments: requests are mandatory
If a quota covers CPU or memory in a namespace, every new pod there must explicitly set requests or limits for that resource. Otherwise the API server rejects the pod. This is one of the most common reasons a deployment that worked in a dev namespace fails in a quota-controlled one, and the fix is the LimitRange above, which injects defaults before the quota check.
When a request is rejected, the control plane returns a 403 Forbidden error, and the message names the violated constraint. Read that message first. It usually tells you the requested amount, what is already used and the limit, so you do not have to guess which line of the quota you hit.
A typical debugging sequence:
- Read the error on the failed Deployment or ReplicaSet:
kubectl describe replicaset <name> -n <namespace>. Pod creation failures show up in the events there, because the ReplicaSet controller is the one denied. - Compare usage to limits:
kubectl describe quota -n <namespace>. - Decide whether the workload is oversized, the quota is too tight, or old objects are holding capacity that should be released.
Using scopes to treat workloads differently
Not every pod in a namespace deserves the same budget. Quotas support scope selectors that apply a quota only to a subset of pods. The documented scopes are BestEffort, NotBestEffort, Terminating, NotTerminating, PriorityClass and VolumeAttributesClass, all listed in the resource quota documentation.
Two practical uses:
- Cap long-running pods separately from batch jobs. Use
TerminatingandNotTerminatingto give run-to-completion work its own pool, so a burst of jobs cannot starve services. - Reserve capacity by priority. A
PriorityClassscope lets you allow a handful of high-priority pods while keeping the bulk of the namespace at normal priority.
A sketch of a priority-scoped quota:
apiVersion: v1
kind: ResourceQuota
metadata:
name: high-priority-pods
namespace: team-a
spec:
hard:
pods: "10"
requests.cpu: "4"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["high"]
Keep scopes few. Every extra quota in a namespace is one more thing a developer must understand when a deploy is denied.
Behaviors that catch administrators off guard
Quotas do not touch existing resources
Changes to a quota apply only to future creates and updates. If you tighten a quota below current usage, running pods keep running, and the namespace sits over its limit until something is recreated. That is safe, but it means a quota edit is not a cleanup tool. Plan the rollout: lower the quota, then restart workloads in a controlled order.
Quotas do not scale with the cluster
Quotas are expressed in absolute units and are independent of total cluster capacity. Add ten nodes and no namespace gets more room. If you want proportional division of cluster resources, the documentation says you need an external controller that watches usage and updates quota objects. In practice many teams simply review quotas after every capacity change and keep the numbers in version control.
Logs can count against ephemeral storage
With a CRI container runtime, container logs count against the local ephemeral-storage quota, per the same documentation. A chatty application can therefore trigger evictions while its own data stays well inside limits. If you quota ephemeral-storage, include log volume in your sizing and check log verbosity before raising the number.
Terminal pods still hold object counts until deleted
A count quota on pods is about objects, not running processes. Completed Jobs that are never cleaned up can keep a namespace near its pod limit. Set ttlSecondsAfterFinished on Jobs, or the history limits on CronJobs, so the count reflects reality.
How to choose the numbers
There is no universal right value, and anyone who gives you one without seeing your workloads is guessing. A method that works:
- Measure first. Look at current requests and actual usage per namespace for a few weeks. Quotas based on requests should sit comfortably above steady-state requests.
- Leave headroom for rollouts. A rolling update briefly runs old and new pods side by side. If a namespace sits at 95% of its CPU request quota, the next deploy may stall.
- Start with requests, add limits deliberately. A quota on
requests.*governs what the scheduler reserves. A quota onlimits.*caps burst potential. Many teams set both, with limits at roughly twice requests, but that ratio is a house policy and not a rule from Kubernetes. - Cap objects that cost money or hurt the control plane. PVC counts, storage totals and LoadBalancer Services are the usual candidates because they translate into cloud bills.
- Write down who can ask for more. A quota with no request process turns into a support queue.
For storage specifically, the storage consumption task shows the split that works well: a LimitRange puts a ceiling on the size of any single claim, while a quota caps what the namespace can claim in total.
If you want a step-by-step exercise before touching a shared cluster, the CPU and memory quota tutorial builds a quota in a throwaway namespace.
Managing quotas across namespaces and clusters
Quota work is mostly reading, not writing. Writing the YAML takes five minutes. The ongoing job is answering questions like: which namespaces are above 80% of their memory request quota, which cluster has the odd LimitRange someone created by hand, and why did this deploy fail in staging but not in production.
With plain kubectl that means switching contexts, repeating describe quota per namespace, and keeping track of which kubeconfig points where. Our guides on Kubernetes namespace management and kubeconfig context management cover habits that reduce the risk of changing the wrong cluster, and the multi-cluster guide covers the wider picture.
Where Kubezilla Desktop fits
Kubezilla Desktop is a native app for Linux, macOS and Windows that puts cluster resources, YAML editing, live logs, metrics and pod terminals in one window, with multi-cluster access and SSH tunneling. Kubeconfigs stay in secure local storage, with no cloud sync or telemetry. When a deploy is denied by a quota, you can open the namespace, edit the quota or LimitRange YAML, and look at the pod logs and metrics without hopping between terminals and browser tabs.
It costs €5 per month. Details are on the pricing page.
Our perspective
We build a tool for people who live in clusters all day, and the quota incidents we hear about are rarely about syntax. They come from invisibility. Someone sets a quota in January, the team grows, and in June a Friday deploy fails because nobody remembers the number or where it lives.
Three opinions we hold, and they are opinions, not Kubernetes rules:
- Treat quotas as product decisions, not guardrails you forget. Each namespace quota should have an owner and a review date.
- Always ship the LimitRange with the quota. A quota without defaults pushes confusing 403 errors onto developers who did nothing wrong.
- Look at quotas from where you work, not only from a CI log. Being able to see usage, edit YAML and read logs in one place shortens the time between a rejected deploy and a fix. That is why we kept Kubezilla Desktop lightweight, written in Rust, and local-first: the app should never be the thing that slows an incident down, and your credentials should never leave your machine.
— Margus
FAQ
What is the difference between a LimitRange and a ResourceQuota?
A ResourceQuota caps the total consumption and object counts of a whole namespace. A LimitRange sets minimum, maximum and default values for each individual pod or container. Use both: the LimitRange keeps single workloads sane and supplies defaults, and the quota keeps the namespace total under control.
Why does my pod fail with a 403 Forbidden after I add a quota?
The request either exceeds the remaining quota or omits CPU or memory requests and limits that the quota now requires. The error message names the violated constraint. If resources are missing, add them to the manifest or create a LimitRange that supplies defaults.
Do resource quotas kill pods that already run?
No. Quotas are checked when objects are created or updated, so existing resources are not restricted by a new or tighter quota. A namespace can stay over its limit until those objects are recreated or modified.
Will my quota grow if I add nodes to the cluster?
No. Quotas are absolute values and have no link to total cluster capacity. To divide capacity proportionally you need an external controller that updates quota objects, or a process to review them after capacity changes.
Can I apply different quotas to different pods in the same namespace?
Yes, with scope selectors. You can scope a quota by criteria such as BestEffort versus NotBestEffort, Terminating versus NotTerminating, or PriorityClass, so batch work and high-priority services draw from separate budgets.
Sources
- Resource Quotas, Kubernetes documentation
- Limit Ranges, Kubernetes documentation
- Limit Storage Consumption, Kubernetes documentation
- ResourceQuota API reference, Kubernetes
- Configure Memory and CPU Quotas for a Namespace, Kubernetes
- Resource Quotas and Limit Ranges, Kubernetes on Azure Workshop
- ResourceQuota vs LimitRange, Stack Overflow
