What Is Little's Law? Capacity Planning Explained
Little's Law relates the number of requests in a system, their arrival rate, and how long each one takes — a simple formula for sizing capacity.
Little’s Law is a simple formula from queueing theory that relates three numbers describing any stable system that processes requests: the average number of items in the system (L), the average rate at which new items arrive (λ), and the average time each item spends in the system (W). The relationship is L = λW — and because it holds for almost any queue-like system regardless of the details of how it’s built, it’s one of the more useful back-of-envelope tools for capacity planning in backend systems.
The formula, and why it needs so few assumptions
Little’s Law states that the average number of requests concurrently “in” a system equals the average arrival rate multiplied by the average time each request spends in that system. If a web service receives 200 requests per second (λ) and each request takes an average of 150 milliseconds to fully process (W = 0.15 seconds), then on average there are L = 200 × 0.15 = 30 requests being handled concurrently at any given moment.
What makes this useful rather than just a curiosity is how few assumptions it requires. It doesn’t matter what the arrival pattern looks like — bursty, uniform, random — and it doesn’t matter what the distribution of processing times looks like, as long as the system is stable (items aren’t piling up faster than they’re being processed, on average, over the period being measured). That generality is exactly why it applies just as well to a web server’s request queue as it does to a physical checkout line: the underlying math doesn’t care what the “items” or “servers” actually are.
Using it for capacity planning
The practical value of Little’s Law shows up when you rearrange it to solve for whichever variable you’re trying to plan around. Given a target throughput and a known average latency, L tells you the minimum concurrency your system needs to sustain — which translates directly into how many worker threads, connection pool slots, or concurrent goroutines you need provisioned to avoid requests queueing up. A service that needs to sustain 500 requests per second with an average response time of 200ms needs to be able to hold roughly 100 requests in flight at once (L = 500 × 0.2); provisioning meaningfully fewer concurrent workers than that means requests start queueing rather than being served immediately, which increases W, which by the same formula further increases L — a feedback loop that’s a common cause of a service’s latency degrading nonlinearly once load crosses a certain threshold rather than degrading gradually.
This is the same underlying reason connection pooling needs to be sized deliberately rather than guessed: a pool sized below the L implied by your actual throughput and latency becomes the bottleneck itself, with requests waiting for a free connection rather than being limited by the database’s real capacity.
Where the “in the system” boundary matters
Applying Little’s Law correctly requires being precise about what counts as “in the system.” L, λ, and W all have to refer to the same boundary — if W is measured as end-to-end client-perceived latency (including time queued behind a load balancer before even reaching a server) but L is measured only as requests currently executing inside application code, the formula’s inputs no longer describe the same system and the relationship breaks down. This is a common source of capacity-planning mistakes: teams measure latency at one boundary and concurrency at another, then get confused when the numbers don’t reconcile.
Drawing the boundary consistently — say, everything from load balancer entry to response delivery — makes Little’s Law directly usable for sizing that whole pipeline, or it can be applied separately, boundary by boundary, to each stage (load balancer, application tier, database) to find which specific stage’s concurrency requirement is the actual bottleneck.
What it doesn’t tell you
Little’s Law describes averages over a stable period; it says nothing about variance, tail latency, or what happens during a burst that temporarily exceeds the system’s capacity to keep up. Two systems with identical average L, λ, and W can behave completely differently under a traffic spike depending on how much slack capacity and buffering they have — Little’s Law doesn’t distinguish a system with smooth, predictable load from one with the same averages but violent bursts, since it operates purely on long-run averages. It’s a sizing tool for planning steady-state capacity, not a substitute for load testing against realistic traffic shapes, and it says nothing at all about Big O-style algorithmic complexity within a single request — the two describe entirely different layers of a system’s performance.
It also assumes a stable system by definition; if arrivals genuinely and persistently exceed processing capacity, L grows without bound and the formula still holds mathematically, but the “average” numbers it’s built from stop meaning anything useful for planning purposes.
Practical use alongside SLOs
Teams that define explicit SLAs, SLOs, and SLIs for a service can use Little’s Law in the other direction: given a latency SLO (a target W) and an expected traffic forecast (λ), it directly implies the minimum concurrency capacity (L) the service needs provisioned to have a realistic chance of meeting that SLO under normal load, before any consideration of horizontal vs. vertical scaling strategy for how that capacity actually gets added.
The takeaway
Little’s Law — L = λW — relates concurrency, arrival rate, and time-in-system for any stable queue-like process, and it holds regardless of the specific arrival pattern or processing-time distribution involved. Its main practical use is capacity planning: given a target throughput and expected latency, it tells you the concurrency a system needs to sustain that combination without requests starting to queue. It’s an averages-only tool, not a substitute for load testing against real traffic bursts, but as a quick sanity check on whether a proposed pool size, worker count, or connection limit is in the right ballpark, it’s hard to beat for how little it requires you to know about the system’s internals.
Keep reading
Chisato · · 4 min read What Is Virtual Memory? Paging and Address Translation
Virtual memory gives every process its own private address space, mapped to physical RAM by the OS and CPU — enabling isolation, swapping, and overcommit.
The Lycoris Team · · 5 min read What Is Backpressure? Flow Control in Streams and Queues
Backpressure is how a slow consumer signals a fast producer to hold off, preventing memory exhaustion in streams, queues, and network protocols.
The Lycoris Team · · 5 min read LRU vs LFU: Cache Eviction Policies Compared
LRU evicts whatever hasn't been used in the longest time; LFU evicts whatever has been used the fewest times. How each policy behaves and when to pick it.