Contents
, where is the long-run average number of items in the system (in queue plus in service), is the long-run average arrival rate (equal to the throughput when the system is stable), and is the average time an item spends in the system; and must use the same time unit.
Deep Breakdown
What it tells me (Situation Awareness): Any stable system that items enter and leave (a support queue, a warehouse, a checkout line, a hiring pipeline, a server request pool) obeys one identity between three averages: how many items are inside, how fast they arrive, and how long each stays. The argument is an accounting one. Plot the number of items in the system over a long window . The area under that curve can be counted two ways: by time, it is ; by item, it is the sum of every item's time in the system, . Equating the two and dividing by gives . Nothing in that argument depends on the arrival distribution, the service distribution, the number of servers or the queue discipline (FIFO, priority, random); it only needs the system to be stable (average arrivals equal average departures) and the window to be long enough that items straddling its edges do not matter. That makes it the most robust law in operations: given any two of , , , the third follows. In DA/DS: estimate cycle time from a WIP snapshot and a throughput count without tracking individual items, sanity-check dashboards (if backlog, intake and resolution time do not satisfy , one metric is wrong), and size staff or capacity from target waiting times.
Flowchart
Real-world use
Where it is used
Customer-support backlog planning, warehouse and manufacturing work-in-progress (WIP) control, retail checkout and call-centre staffing, Kanban and software-delivery metrics (WIP limits, lead time), hospital bed occupancy, inventory turnover (), recruitment pipelines, and capacity planning for web servers and database connection pools.
Problem it solves
Time in system is often the metric that matters (customer wait, order lead time, ticket resolution time) but it is expensive to measure item by item. Counts in the system and arrival rates are cheap: a snapshot and a counter. Little's Law converts the cheap metrics into the expensive one and exposes inconsistent reporting.
How it solves the problem
Because holds for averages regardless of distributions, it turns a snapshot into a duration () and a target duration into a capacity requirement (). For a fixed intake, the only way to cut time in system is to cut the number of items in the system, which is the logic behind WIP limits. Combined with a queuing model (for example M/M/c) it also shows how fast and grow as utilisation approaches .
Example in a business
A support desk receives tickets per day and has open tickets: average resolution time is days. To meet a 1-day target at the same intake, the open backlog must fall to . A fulfilment centre ships orders per hour with orders in progress on the floor, so the average order spends hours from release to dispatch; capping WIP at at the same throughput brings that to hours. A supermarket with tills, customers per minute and minutes per customer (utilisation ) averages customers at the checkout and minutes each; at customers per minute (utilisation ) the same tills average customers and minutes.
The formula, piece by piece
- : average number of items in the system over time (time-average of ), including those being served; work-in-progress, backlog, occupancy
- : average arrival rate, items per unit time; in a stable system equal to the departure rate (throughput)
- : average time in system per item, from arrival to departure (lead time, cycle time, sojourn time)
- Units: in items per day with in days gives in items; mixing hours and days is the most common error
- Queue-only version: , with items waiting and time waiting before service
- Service-only version: , the average number in service, where is the mean service time
- Stability: arrivals and departures balance over the window; for a queue with servers this requires
- Rearrangements: and
The formula in words
"The average number of things in a system equals how fast they arrive times how long each one stays." Tiny example: a café serves customers per hour and each stays minutes ( hour) on average, so on average customers are inside.
Critical Concepts
- Distribution-free: the law holds for any arrival process, service-time distribution, number of servers and queue discipline. It does not say what will be, only how , and relate.
- Averages only: it does not give the distribution of waiting times; a mean of days can hide a tail of tickets open for weeks. Report percentiles separately.
- Stability required: if arrivals exceed capacity, the backlog grows without bound and the long-run averages do not exist. Over short windows with a growing or shrinking backlog, use the boundary-corrected form or a longer window.
- Consistent boundaries: , and must describe the same system (for example, queue plus service, or queue only) and the same population of items.
- Utilisation drives waiting: in an M/M/c queue, raising utilisation from to with 5 servers multiplies by about () while rises only by a factor of , so by Little's Law rises by about ( minutes).
- WIP limits: for a fixed throughput, lead time is proportional to WIP; reducing work started is the direct lever on lead time (Kanban, CONWIP).
- Inventory link: stock on hand usage rate average days in stock, so inventory turnover and days of supply are Little's Law applied to goods (see Economic Order Quantity (EOQ)).
Step-by-step calculation (tiny example)
A support desk logs 10 tickets in a 10-hour day, all closed before the end of the day.
Step 1: Arrival rate ticket per hour.
Step 2: Time in system Opened and closed times give durations hours. Sum h, so h.
Step 3: Apply the law open tickets on average.
Step 4: Check by direct measurement The area under the open-ticket curve over the day is the sum of the durations, ticket-hours; divided by the -hour window that is . Both routes agree exactly because every ticket opens and closes inside the window.
Step 5: Use it in reverse A queue at tickets per day with a backlog of implies days.
Code examples
Beginner example (Python)
import numpy as np
import pandas as pd
# Support tickets over one 10-hour day: opened and closed times (hours)
tickets = pd.DataFrame({
"opened": [0.0, 0.5, 1.0, 2.0, 3.0, 4.5, 5.0, 6.0, 7.0, 8.0],
"closed": [1.5, 2.5, 2.0, 5.0, 4.0, 6.5, 7.5, 7.0, 9.0, 9.5],
})
T = 10.0 # observation window (hours)
tickets["time_in_system"] = tickets["closed"] - tickets["opened"]
lam = len(tickets) / T # arrival rate (tickets per hour)
W = tickets["time_in_system"].mean() # average time in system (hours)
print(f"lambda = {lam:.2f} tickets/hour, W = {W:.2f} hours")
print(f"Little's Law: L = lambda * W = {lam * W:.2f} open tickets on average")
# Measure L directly: time-average of the number of open tickets
grid = np.linspace(0, T, 100_001)
open_count = ((tickets["opened"].values[:, None] <= grid) &
(grid < tickets["closed"].values[:, None])).sum(axis=0)
print(f"Measured time-average L = {open_count.mean():.2f}")
# Rearranged: the average wait implied by a backlog
backlog, rate = 180, 120 # open tickets, tickets per day
print(f"\nBacklog {backlog} at {rate}/day -> W = L / lambda = {backlog / rate:.1f} days")Beginner example (R)
opened <- c(0.0, 0.5, 1.0, 2.0, 3.0, 4.5, 5.0, 6.0, 7.0, 8.0)
closed <- c(1.5, 2.5, 2.0, 5.0, 4.0, 6.5, 7.5, 7.0, 9.0, 9.5)
T_window <- 10 # hours observed
lambda <- length(opened) / T_window # 1 ticket per hour
W <- mean(closed - opened) # 1.75 hours
L <- lambda * W
cat(sprintf("lambda = %.2f/h, W = %.2f h, L = %.2f tickets\n", lambda, W, L))
# Direct time-average of the number of open tickets
grid <- seq(0, T_window, length.out = 100001)
open_count <- sapply(grid, function(t) sum(opened <= t & t < closed))
cat(sprintf("measured L = %.2f\n", mean(open_count)))
# Warehouse: cycle time from WIP and throughput
wip <- 1000; throughput <- 400 # orders, orders per hour
cat(sprintf("cycle time W = %.1f hours\n", wip / throughput))Professional example (Python)
import math
import numpy as np
rng = np.random.default_rng(3)
def simulate_checkout(lam, mu, c, n_customers):
"""First-come-first-served queue with c tills; Poisson arrivals, exponential service."""
arrivals = np.cumsum(rng.exponential(1 / lam, n_customers))
service = rng.exponential(1 / mu, n_customers)
free_at = np.zeros(c) # when each till becomes free
departures = np.empty(n_customers)
for i in range(n_customers):
k = np.argmin(free_at)
start = max(arrivals[i], free_at[k])
departures[i] = start + service[i]
free_at[k] = departures[i]
return arrivals, departures
def time_average_in_system(arrivals, departures, t0, t1):
"""Exact integral of N(t) over [t0, t1] divided by the window length."""
overlap = np.clip(np.minimum(departures, t1) - np.maximum(arrivals, t0), 0, None)
return overlap.sum() / (t1 - t0)
def erlang_c_L(lam, mu, c):
"""Theoretical mean number in an M/M/c system."""
a, rho = lam / mu, lam / (c * mu)
tail = a ** c / (math.factorial(c) * (1 - rho))
p_wait = tail / (sum(a ** k / math.factorial(k) for k in range(c)) + tail)
Lq = p_wait * rho / (1 - rho)
return Lq + a
lam, mu, c = 2.0, 0.5, 5 # 2 customers/min, 2 min per customer, 5 tills
arr, dep = simulate_checkout(lam, mu, c, 200_000)
t0, t1 = arr[10_000], arr[-10_000] # drop warm-up and the unfinished tail
inside = (arr >= t0) & (arr < t1)
L = time_average_in_system(arr, dep, t0, t1)
lam_hat = inside.sum() / (t1 - t0)
W = (dep - arr)[inside].mean()
print(f"utilisation rho = {lam / (c * mu):.2f}")
print(f"measured L = {L:.3f}")
print(f"lambda_hat * W = {lam_hat:.3f} x {W:.3f} = {lam_hat * W:.3f}")
print(f"Erlang C theory L = {erlang_c_L(lam, mu, c):.3f}")
# Planning: what happens to queue length as arrivals grow, tills fixed at 5
for lam_test in (1.5, 2.0, 2.25, 2.4):
L_th = erlang_c_L(lam_test, mu, c)
print(f"lambda={lam_test:.2f}/min, rho={lam_test / (c * mu):.2f}: "
f"L={L_th:6.2f}, W=L/lambda={L_th / lam_test:5.2f} min")The simulated 5-till checkout (Poisson arrivals at per minute, exponential service with mean minutes, utilisation ) gives a measured time-average of customers in the system and : Little's Law holds on the simulated data to three decimals, with no assumption about the queue beyond stability. The Erlang C formula predicts ; the gap is sampling noise in the simulation, not a failure of the law. The planning table shows the non-linear cost of utilisation: as arrivals rise from to per minute ( from to ), average time in the system rises from to minutes, and the average number of customers at the tills from to .
Source: domain knowledge