Kubernetes requests reserve capacity for scheduling, while limits define runtime resource ceilings for containers.
That difference sounds small, but it affects where Pods can run, how CPU contention is handled, what happens under memory pressure, and how resource-based autoscaling interprets workload demand. For small teams using Raff Kubernetes, inaccurate requests can also make worker capacity look exhausted earlier than it really is, while missing limits can leave shared workloads with fewer runtime boundaries.
This guide owns the requests-versus-limits decision inside the Kubernetes Cluster Management for Small Teams operating model. It explains CPU and memory behavior, units, defaults, Quality of Service implications, autoscaling signals, and a practical sizing framework without duplicating the broader Kubernetes Cost Optimization guide.
At Raff, the resource review starts with requests, not limits. Requests are the numbers the scheduler and resource-based scaling logic trust; if they are guesses, the cluster can make expensive placement decisions from bad inputs.
Kubernetes requests and limits control different decisions
Requests and limits belong in the same resource block, but Kubernetes uses them for different purposes.
resources: requests: cpu: "250m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi"
In this example, the container requests 0.25 CPU and 256 MiB of memory. Its CPU limit is 0.5 CPU and its memory limit is 512 MiB.
The important distinction is operational:
| Setting | Main purpose | What Kubernetes does with it |
|---|---|---|
| CPU request | Scheduling and CPU weighting | Scheduler uses it for placement; under contention it influences relative CPU allocation |
| Memory request | Scheduling | Scheduler uses it when deciding whether the Pod fits on a node |
| CPU limit | Runtime ceiling | CPU use above the limit is throttled |
| Memory limit | Runtime ceiling | Memory above the limit can lead to out-of-memory termination under pressure |
A request is not a prediction of exact usage. It is a capacity statement the scheduler can act on.
A limit is not extra reserved capacity. It is a boundary on runtime resource use.
Requests are scheduling inputs; limits are runtime boundaries. Treating them as interchangeable produces both reliability and cost problems.
Requests drive scheduling before actual usage is known
The Kubernetes scheduler places a Pod by comparing its requests with available node capacity. It does not wait to see how little CPU or memory the workload happens to use after startup.
That is why inflated requests reduce placement efficiency.
Imagine four application Pods, each requesting 500m CPU:
4 Pods × 500m CPU = 2000m = 2 CPU requested
Those requests add up to 2 CPU before accounting for node-level system overhead or any other workloads. You should therefore not assume those four Pods all fit safely on a worker advertised as 2 vCPU simply because their measured CPU use is usually lower.
The reverse problem is equally important. If a workload requests far less than it normally needs, Kubernetes may place too many CPU- or memory-active workloads together. The node can look schedulable on paper while contention appears later at runtime.
This creates two different failure patterns:
- Requests are too high: Pods become unschedulable sooner, node utilization is lower, and more worker capacity may be added than the workload actually needs.
- Requests are too low: placement looks efficient, but workloads compete harder after scheduling and operational signals become less trustworthy.
A high request can buy capacity you never use. A low request can make contention and autoscaling behavior misleading.
For cluster-wide capacity planning, continue with Kubernetes Cluster Sizing. For workload separation, Kubernetes Node Pools owns the placement and isolation decision.
CPU and memory limits fail in different ways
CPU and memory are not enforced the same way, so one universal limits policy is usually too simplistic.
A CPU limit is a hard runtime ceiling. When a container tries to use more CPU than its configured limit, the runtime and kernel enforce the boundary through CPU throttling. The process usually keeps running, but it receives less CPU time than it wants.
That can be useful for noisy-neighbor containment. It can also hurt latency-sensitive workloads if the limit is lower than legitimate burst demand. Kubernetes documentation explicitly notes this trade-off: CPU limits can prevent one workload from consuming excessive CPU, but they can also throttle a container even when spare CPU exists on the node.
A memory limit behaves differently. Memory is not throttled in the same gradual way. Enforcement is reactive: if a container exceeds its available memory boundary and the kernel encounters memory pressure, the container can be terminated with an out-of-memory condition.
That means:
CPU limit exceeded → throttling Memory limit exceeded → possible OOM termination
The production question is therefore not simply “Should every request equal every limit?”
For CPU, decide how much burst capacity the workload should be allowed to use and whether strict containment is more important than burst performance.
For memory, decide how much growth the process can safely tolerate before termination is preferable to allowing it to consume more node memory.
Avoid universal ratios such as setting every limit to exactly twice the request. Different applications have different CPU burst patterns, memory working sets, startup behavior, garbage collection, and failure costs.
Units and implicit defaults create common configuration mistakes
Resource values are easy to misread because CPU and memory use different units.
For CPU:
1 CPU = 1 CPU core or 1 virtual core 500m = 0.5 CPU 250m = 0.25 CPU 100m = 0.1 CPU
MilliCPU notation is especially useful below one CPU. 100m means one tenth of a CPU, not 100 CPUs.
Memory quantities are byte-based and commonly use binary suffixes such as Mi and Gi:
256Mi 512Mi 1Gi
One subtle but serious mistake is confusing CPU-style m notation with memory. Kubernetes documentation calls out that a memory value such as 400m means 0.4 bytes, not 400 MiB. Use the intended memory unit explicitly.
Another important default appears when a container has a limit but no request. If no admission-time defaulting mechanism supplies a request, Kubernetes can copy the limit value into the request for that resource.
That means this configuration:
resources: limits: cpu: "1"
can effectively become a 1-CPU scheduling request as well. A team intending only to cap runtime CPU can accidentally reserve much more scheduling capacity than expected.
Namespace policy can also change the outcome because a LimitRange can inject default requests and limits. Always inspect the effective workload configuration rather than assuming omitted fields remain unset.
Requests influence QoS and autoscaling signals
Requests and limits affect more than initial scheduling.
Kubernetes uses resource configuration as part of Pod Quality of Service classification. Pods with no CPU or memory requests or limits can fall into the BestEffort class, while other combinations produce Burstable or, under stricter equal request/limit conditions, Guaranteed behavior. Those classes influence eviction priority when a node is under resource pressure.
For small teams, the practical lesson is not to chase a QoS label in isolation. Set resource values that accurately represent the workload and then understand the resulting failure behavior.
Requests also matter directly to the Horizontal Pod Autoscaler when utilization targets are used.
For CPU utilization, HPA compares observed CPU use with the configured CPU request. A simplified view is:
CPU utilization = measured CPU use / CPU request
If a container has no relevant CPU request, resource-utilization calculation can be undefined for that workload and HPA may not act on that metric as expected.
This creates a common scaling problem:
Actual CPU use: 200m CPU request: 100m Reported utilization: about 200%
versus:
Actual CPU use: 200m CPU request: 500m Reported utilization: about 40%
The application is doing the same amount of CPU work in both examples, but the scaling signal is very different because the request changed.
That is why the future autoscaling decision must start with honest requests. Autoscaling cannot compensate reliably for arbitrary resource baselines.
The decision framework starts from observed workload behavior
Requests and limits should come from measurements and failure requirements, not copied templates.
Use this framework as a starting point.
| Evidence | Request decision | Limit decision |
|---|---|---|
| CPU is steady with occasional harmless bursts | Set request near sustained useful demand | Allow measured burst headroom if isolation permits |
| CPU is highly bursty and latency-sensitive | Avoid reserving for every short peak | Test whether a strict CPU ceiling causes throttling |
| Memory working set is predictable | Request enough for normal working set plus justified headroom | Set a boundary above observed peaks and test OOM behavior |
| Memory grows without stabilizing | Do not hide the problem with a large request | Use a limit as containment while fixing the cause |
| Batch job can tolerate slower completion | Request realistic baseline capacity | CPU ceiling can protect neighboring workloads where useful |
| Critical service must survive contention | Request enough capacity to reflect importance | Choose limits from failure policy, not a generic ratio |
| Usage data is missing | Start conservatively and measure | Avoid claiming the initial values are final |
The review process should use several windows, not one quiet sample. Capture normal load, peak traffic, startup, deployment overlap, scheduled jobs, and failure recovery.
For each workload, record:
- Typical CPU usage
- Peak CPU usage and burst duration
- Typical memory working set
- Peak memory and startup behavior
- Replica count under normal and peak demand
- User impact when CPU is throttled
- User impact when a process is OOM-killed
At Raff, we prefer a resource value tied to observed behavior over a “safe” round number. A 500m request with evidence is more useful than a 1-CPU request chosen only because it feels conservative.