Mert Özen Further With Every Line
Project Management Kanban — #03

WIP Limits and Little's Law: Start Less, Finish More

Mert Özen Nov 8, 2026 11 min 3 views
WIP Limits and Little's Law: Start Less, Finish More

With throughput fixed, raising WIP stretches cycle time by the same factor; Little's Law is the arithmetic behind it. In our C# simulation, raising WIP from 3 to 10 takes average cycle time from 2.4 to 7.9 days, and adding context switching cuts throughput too. We cover Little's Law's assumptions, why it is not a forecasting tool, how to set a first WIP limit and pitfalls like per-person limits.

Version note: This post is based on version 2025.5 of The Kanban Guide; the simulation code was built and run with .NET 10.

Guess First

Picture a team of three developers. They finish about 6 items a week on average and that number hasn't changed for months; assume work comes from an endless backlog and nobody goes on holiday. For a while the team runs at most 3 items at a time. Then, so that "everyone always has something waiting and nobody sits idle," they raise the limit to 10. Throughput stays the same: still 6 items finished per week.

What happens to the average time an item takes from start to finish? Does it stay the same, grow a little, or triple? And consider this: how realistic is the assumption that throughput stays the same when the number of items each person has open at once goes up?

Little's Law: Three Numbers, One Equation

In a 1961 paper in the journal Operations Research, John Little gave the proof of the queueing equation that now bears his name: L = λW. The average number of items in the system (L) equals the average arrival rate (λ) times the average time an item spends in the system (W). The average number of customers in a bank equals the number of customers arriving per minute times the average minutes a customer stays.

In Kanban this equation is usually written with flow metrics:

average cycle time = average WIP / average throughput

If a team runs an average of 10 items at once and finishes an average of 1.25 items a day, an item stays in the system for 8 working days on average. The formula is simple; its real value is showing how the other two numbers must move when you change one of them. Changing throughput is hard: it takes more people, less work, better tools. Changing WIP (Work in Progress) is a decision the team can make today. If you halve WIP while throughput stays fixed, average cycle time halves too.

Code: Same Team, Different WIP Limits

Showing this with a formula is easy, but seeing it in a simulation is more convincing. The .NET 10 console app below simulates a three-developer team hour by hour. The backlog never runs dry; new work is pulled while the WIP limit isn't full. The effort each item needs comes from a lognormal distribution with a median of 2 working days, so most work takes 1–3 days with the occasional 6–8 day item. Team capacity is split evenly across the items open at that moment, but no item can have more than one person on it at a time:

public static class BoardSimulation
{
    const int Developers = 3;
    const int WarmUpDays = 100;
    const int MeasuredDays = 2000;

    public static SimResult Run(int wipLimit, double switchCost, int seed = 7)
    {
        Random rng = new(seed);
        List<(int StartHour, double Remaining)> wip = [];
        List<double> cycleTimes = [];
        long wipHours = 0;

        // Time advances hour by hour: 1 working day = 8 hours
        for (int hour = 0; hour < (WarmUpDays + MeasuredDays) * 8; hour++)
        {
            bool measuring = hour >= WarmUpDays * 8;

            // Pull: take new work from the backlog until the limit is reached (the backlog never runs dry)
            while (wip.Count < wipLimit)
                wip.Add((hour, Effort(rng)));

            if (measuring)
                wipHours += wip.Count;

            // As items per person grow, context switching eats part of the day
            double itemsPerPerson = (double)wip.Count / Developers;
            double efficiency = Math.Max(0.1, 1 - switchCost * Math.Max(0, itemsPerPerson - 1));
            double share = Math.Min(1.0, Developers * efficiency / wip.Count) / 8;

            for (int i = wip.Count - 1; i >= 0; i--)
            {
                (int start, double remaining) = wip[i];
                remaining -= share;
                if (remaining > 0)
                {
                    wip[i] = (start, remaining);
                    continue;
                }

                wip.RemoveAt(i);
                if (measuring)
                    cycleTimes.Add((hour - start + 1) / 8.0);
            }
        }

        cycleTimes.Sort();
        return new SimResult(
            AvgWip: (double)wipHours / (MeasuredDays * 8),
            ThroughputPerWeek: cycleTimes.Count / (MeasuredDays / 5.0),
            AvgCycleTime: cycleTimes.Average(),
            P85CycleTime: (int)Math.Ceiling(cycleTimes[(int)Math.Ceiling(0.85 * cycleTimes.Count) - 1]));
    }

    // Item effort: lognormal with a median of 2 working days, a few big items stretch the tail
    static double Effort(Random rng)
    {
        double u1 = 1.0 - rng.NextDouble(), u2 = rng.NextDouble();
        double normal = Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2);
        return 2.0 * Math.Exp(0.6 * normal);
    }
}

The second parameter, switchCost, models the cost of context switching: once a person has more than one open item, each extra item eats 10% of that person's day. In the first run this cost is zero, a completely ideal world. The top of the program tries four limits in two scenarios and prints the cycle time Little's Law predicts in the last column:

using System.Globalization;

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

Console.WriteLine("WIP limit | avg WIP | throughput/week | avg cycle time | p85 cycle time | Little: WIP / TP");
foreach (int limit in new[] { 3, 5, 8, 10 })
    Print(limit, BoardSimulation.Run(wipLimit: limit, switchCost: 0.0));

Console.WriteLine();
Console.WriteLine("Same board, each extra item per person costs 10% of that person's day:");
foreach (int limit in new[] { 3, 5, 8, 10 })
    Print(limit, BoardSimulation.Run(wipLimit: limit, switchCost: 0.10));

static void Print(int limit, SimResult r) =>
    Console.WriteLine($"{limit,9} | {r.AvgWip,7:F1} | {r.ThroughputPerWeek,15:F1} | {r.AvgCycleTime,11:F1} d | " +
        $"{r.P85CycleTime,11} d | {r.AvgWip / (r.ThroughputPerWeek / 5),8:F1} d");

public sealed record SimResult(double AvgWip, double ThroughputPerWeek, double AvgCycleTime, int P85CycleTime);

The real output:

WIP limit | avg WIP | throughput/week | avg cycle time | p85 cycle time | Little: WIP / TP
        3 |     3.0 |             6.2 |         2.4 d |           4 d |      2.4 d
        5 |     5.0 |             6.3 |         4.0 d |           6 d |      4.0 d
        8 |     8.0 |             6.3 |         6.3 d |          10 d |      6.3 d
       10 |    10.0 |             6.3 |         7.9 d |          12 d |      7.9 d

Same board, each extra item per person costs 10% of that person's day:
        3 |     3.0 |             6.2 |         2.4 d |           4 d |      2.4 d
        5 |     5.0 |             5.9 |         4.3 d |           7 d |      4.3 d
        8 |     8.0 |             5.3 |         7.5 d |          12 d |      7.5 d
       10 |    10.0 |             4.9 |        10.2 d |          16 d |     10.2 d

Reading the Output

In the first table throughput barely moves: between 6.2 and 6.3 items a week. Same capacity, same work; only the number of items kept open at once changes. But average cycle time goes from 2.4 days to 7.9 days; multiply WIP by 3.3 and cycle time multiplies by roughly 3.3 too. The 85th percentile, the number that matters to a customer, jumps from 4 days to 12. Little's Law's prediction in the last column matches the simulated average exactly, because this system satisfies Little's Law's assumptions perfectly: every item that starts finishes, and the system runs under the same conditions for a long time.

What this table says is counterintuitive: at a limit of 10 nobody is idle, everyone has work waiting, yet nothing finishes faster. The team looks busier and the customer waits longer. Everyone having work and work flowing are not the same thing.

The second table leaves the ideal world. Assuming each extra open item per person eats 10% of the day, throughput at a limit of 10 drops to 4.9 items a week and average cycle time rises to 10.2 days. So high WIP hits you twice: each item waits longer and the total work finishes more slowly. The 10% is an assumption we chose, not a measured constant. The famous table in Gerald Weinberg's 1992 book "Quality Software Management: Systems Thinking" suggests that a second project costs a person about 20% of their time to context switching; our number is half that, so it is optimistic.

Why Little's Law Is Not a Calculator

In the simulation Little's Law worked perfectly. On a real board it won't be this clean, because its assumptions break. In "Actionable Agile Metrics for Predictability" (2015), his book on flow metrics, Daniel Vacanti lists these assumptions in team terms; they appear with small differences in different sources:

  • Over the measured period, the average arrival rate must equal the average departure rate.
  • Every item that starts must eventually finish and leave the system; nothing gets abandoned halfway and forgotten.
  • WIP at the start and end of the period should be roughly the same.
  • The average age of the items in WIP should be neither steadily increasing nor decreasing.
  • All three metrics must use consistent units: if WIP is in items, throughput is items/day and cycle time is days.

When these assumptions break, the formula produces wrong numbers. That is why using Little's Law to forecast, saying "WIP is 12, throughput is 1.2 a day, so new work will finish in 10 days," is dangerous. Vacanti also stresses that Little's Law should be used to understand how a system behaves, not as a forecasting tool. For forecasting we will use the Monte Carlo simulation in post 05. What Little's Law tells you is the direction: if WIP goes up and throughput stays the same, cycle time must go up. That is not an opinion, it is arithmetic.

There is also a reverse use: checking Little's Law against your own data. Compute average WIP, throughput and cycle time from your board separately. If there is a big gap between WIP / throughput and the average cycle time you measured, either the system is not stable (WIP keeps growing) or there is a problem in your data: abandoned work still sitting on the board, transition dates recorded wrongly and so on.

Stop Starting, Start Finishing

There is a slogan the Kanban community repeats a lot: "Stop starting, start finishing." Little's Law is the math behind that slogan. When a developer pulls new work because their current item is waiting in code review, WIP goes up by one. When everyone does this every day, WIP grows, throughput stays the same and cycle time gets longer.

A WIP limit puts a brake on that behavior. When the limit is full, the developer has two options: help an item that is waiting (review a PR (pull request), run a scenario with the tester, try to remove the obstacle in front of a blocked item) or, if there really is nothing to do, stay idle. The second sounds bad, but in most teams there is plenty to do when the limit is full; it's just that nobody looks at it, because starting new work is more fun.

Setting Your First WIP Limit

Which number should you start with? There is no ideal formula, but there is a method that works:

First, measure today. For two or three weeks, write down the number of items between started and finished on the board every day and take the average. On the Bookstore team's old board this number was 13–14; the team set its first limit at 14, which wrote down the current state without changing anything. In practice that limit almost never kicked in, but it made the number visible to the team.

Then lower it slowly. Reduce the limit by one or two and wait a few weeks. Look at cycle time, throughput and the "limit's full, what do we do?" moments. If cycle time shrinks without throughput dropping, you're heading in the right direction. If the team is often idle and throughput drops, you have lowered the limit too far. In September the Bookstore team lowered the total limit to 12 and added per-column limits; we will see the result with data in post 06.

Finally, use the moment the limit is exceeded as a signal. A limit is not a rule but a conversation starter; asking "why?" when it is exceeded is worth more than the limit itself.

In Production

Don't mix units. Our simulation works in working days; real board data is in calendar days. If you compute throughput as "items per week" and cycle time in "calendar days" and plug them into Little's Law, weekends will give you a gap of up to 40%. Convert everything to the same units: items per calendar day and calendar days.

Don't trust the average. In the simulation there was a 1.5–2x gap between average cycle time and the 85th percentile, and in real data the gap is bigger. Little's Law works with averages, but if you tell a customer "8 days on average," you will miss that promise for roughly half of the items. Percentiles and distributions are the topic of post 04.

Don't leave the limit to the tool to enforce. Jira paints a column red when its limit is exceeded but stops nobody. Whether a limit works depends on the team's behavior, not the tool's; if the policy in the DoW (Definition of Workflow) says "if the limit is full, don't pull new work, help the items to the right," someone has to ask about it every day at the Daily or in front of the board.

Common Pitfalls

A per-person WIP limit is the most common pitfall. "Everyone works on at most 2 items at a time" looks fair, but it splits the team into individual queues. Everyone focuses on their own two items, nobody helps with someone else's work waiting in code review, and the collaboration that is the point of the limit is lost. Put the limit at the column or team level; if you really need a per-person limit, put it next to the team limit, not instead of it.

The second pitfall is nobody doing anything when the limit is exceeded. The limit is 12, there are 15 cards on the board and life goes on. At that point the limit is decoration. Either move the limit to a realistic number or write down as a policy what happens when it is exceeded, and follow it.

The third is dropping blocked items from WIP. If you stop counting an item that waits for an external API (Application Programming Interface) provider because "we aren't working on it anyway," the team starts new work in its place and WIP quietly grows. Blocked work still takes up space in the system and keeps aging.

The fourth is using Little's Law for a single item. The formula works with averages; it does not answer "when will this item be done?" For a single item, the answer is the SLE (Service Level Expectation) and Work Item Age.

A Small Experiment

★☆☆ Run the simulation with Developers = 5 and set the limits to 5, 8, 12, 16. How much does throughput change, and how does cycle time grow? Does the Little's Law column still match the measured average?

★★☆ Raise the sigma of the lognormal in the Effort method from 0.6 to 1.0. How does the gap between average cycle time and the 85th percentile change? What does that mean for a team whose item sizes vary a lot?

★★★ Add a "blocked" probability to the simulation: each item has an 8% chance of a 2–9 day stretch with no progress at all, and a blocked item keeps counting toward WIP. Then write a second version that drops blocked items from WIP and compare WIP, throughput and cycle time between the two versions.

Little's Law spoke in averages. In the next post we leave the average behind and look at the distribution: we will compute the four flow metrics from six months of the Bookstore team's board data with a .NET 10 console app and learn to read percentiles and Work Item Age.