Flow dynamics · 04

The process constraint

For any process made of sequential steps, one step sets the pace for the whole system — the constraint. No matter how fast the other steps run, work can only leave as quickly as the constraint passes it through.

By Gavan Grenville-HuntInteractive guideFlow system map

The simulator below models a production line with four steps in series. Each step has a throughput — the number of items it can complete per minute — set by its slider. The throughput of the whole line equals the throughput of its slowest step, since nothing can leave faster than that step passes it through. That step is the constraint.

returned to backlog0
Committed
normal
Development
normal
Review
normal
Release
normal
Constraint
Process rate
Constraint rate
Cycle time
WIP
Mode
in progressqueuedconstraintblockedstarved

Each slider sets one step’s throughput in items per minute. The lowest-throughput step is the constraint, outlined in purple; steps downstream that run out of work are marked starved. Total WIP and Rate × CT stay equal — Little’s Law.

Try it — six experiments
  1. Reduce the Review throughput to around 12/min
    completion rate falls to match

    Review becomes the constraint — outlined in purple. Work accumulates in front of it, Release starves, and the whole line’s completion rate drops to match Review’s throughput regardless of how fast the other steps run.

  2. Improve a step that is not the constraint
    output unchanged

    Raise the throughput of any step other than the slowest. The completion rate does not change. Making a step faster that was never the bottleneck produces more local activity but no additional output from the system.

  3. Improve the constraint itself
    output rises until next constraint

    Raise the throughput of the slowest step. The completion rate rises with it — until another step becomes the slowest, and the constraint moves there. Throughput improves only when the improvement is at the constraint.

  4. Watch the accumulation
    WIP and cycle time rise together

    While a constraint exists, work arrives faster than it clears, so WIP builds in front of it and cycle time rises with it — the product of throughput rate and cycle time tracks Total WIP, per Little’s Law. Beyond a point, excess work is pushed back to the backlog.

  5. Watch the constraint move
    a new step becomes the bottleneck

    Reset. Slow Review to 15 — Review becomes the constraint and output drops to 15/min. Raise Development to 45: output is unchanged. Now drop Committed to 20 and raise Review to 25. Completion rate rises to 20/min and stops — the constraint badge shifts from Review to Committed. Fixing one bottleneck revealed the next one.

  6. Compare the three WIP handling modes
    same constraint, different response

    Set Review to 15/min and leave the others at 30. Switch between the modes and watch what changes.

    • Block — upstream stages fill and hold. Work is preserved but cycle time rises as the queue builds in front of Review.
    • Push — work arrives faster than the constraint clears it. WIP climbs until items are abandoned mid-pipeline; the abandoned count ticks up and throughput falls below 15/min because capacity is wasted re-doing returned work.
    • Pull — nothing enters until the constraint completes. WIP stays flat, cycle time is minimal, throughput hits 15/min cleanly.

    Same constraint rate in all three — what differs is how much capacity is lost responding to it.

Finding your constraint

Open the board and look for two signals: overload — one stage with work stacked up in it — or starvation — a stage that often sits empty, waiting for the previous step to send something. The overloaded stage is the constraint. A starved stage points one step back: the step before it is the one that can’t keep up.

The constraint moves when you fix it. Speed up Review and Development may become the constraint, or Release. Each time you raise the slowest step, the next slowest one takes over. Find it, raise it, repeat.

There is one less obvious case: when all steps are at roughly the same rate except one that is notably faster. Work doesn’t queue at the fast step — it clears immediately and that stage starves, waiting for input. The constraint is the step directly before it. In most software pipelines this shows up as automated deployment: if Release is near-instant, Review becomes the visible constraint — the last slow step feeding a stage that is always ready to receive.

Completion rate equals the constraint’s throughput

The completion rate is how fast finished work leaves the line. At steady state it equals the throughput of the constraint, because no work can leave faster than the slowest step passes it through. The line’s output is the smallest of the step throughputs, and it can only be raised by raising that step.

Since every step’s slider and the completion-rate readout are in the same units, this can be read directly from the simulator: the completion rate settles on the constraint step’s value regardless of how the other steps are set. A step being fully occupied is not evidence that it contributes to output. Development can be flat-out productive while adding nothing to what the system ships, if Review is the constraint.

Completion rate of the line = throughput of its slowest step. Improving any other step changes local activity, not output.

Accumulation before the constraint, starvation after it

The constraint divides the line into two halves that behave differently. Upstream steps fill to their limit and cannot pass work on because the constraint isn’t ready to receive it — back-pressure propagates upstream as each step in turn fills up.

On a dev team with Review as the constraint, this looks like PRs stacking up while developers either start new tickets — building WIP — or sit idle waiting for review slots. Downstream of the constraint, Release sits idle too: it finishes what Review releases and then waits for the next one.

Upstream of the constraint, steps fill and block. Downstream of it, steps starve.

Why WIP grows, and the return to backlog

When work is committed faster than the constraint can clear it, the difference between the arrival rate and the completion rate accumulates as queue in front of the constraint. Total WIP rises roughly linearly for as long as the overload continues, without settling.

In the simulator, once WIP exceeds what the board can hold, items are returned to the backlog. This reflects a real outcome: work committed without the capacity to complete it does not get done sooner for having been started. It waits, ages, and is often deferred. Committing it earlier mainly increases WIP.

The control is to admit work at the constraint’s rate rather than faster. When the arrival rate matches the completion rate, WIP stabilises and cycle time stops rising — a direct consequence of Little’s Law.

Improving a non-constraint does not help

Increasing the throughput of any step other than the constraint does not increase the output of the system. The most common version of this on a software team: Review is the constraint and the response is to hire more developers. More developers produce PRs faster — but Review still processes them at the same rate. The PR queue grows, WIP rises, cycle time rises with it. Output is unchanged.

If the improved step is upstream of the constraint, it produces work the constraint can’t absorb — WIP and cycle time grow. If it’s downstream, it finishes its work sooner and then waits: it starves more of the time than before.

In both cases the completion rate is unchanged. Only raising the throughput of the constraint itself raises the output of the whole system.

Upstream improvements overwhelm the constraint and make WIP and cycle time worse. Downstream improvements only starve sooner.

Direct all improvement at the constraint

Know where the constraint is before deciding where to invest. Hiring more developers or refactoring a non-constraint step changes local metrics — step throughput, individual utilisation rates — without moving system output.

When you do raise the constraint, output rises until another step takes over. The constraint moves. Find it again, raise it, repeat. Each pass lifts what the pipeline can deliver.

The constraint also shifts with the type of work in the pipeline. Under an incident, Development — diagnosis and fix — becomes the constraint. A large coordinated release may leave Development and Review moving fast while work stacks behind a controlled deploy window. Same team, same pipeline, different constraint: determined by what is flowing through it.

Cross-team dependencies make this harder to see. When a frontend team waits on a backend API, or a product team waits on a platform team for infrastructure, the constraint may not live in either team’s own pipeline. Your steps could all have spare capacity while the system is blocked at another team’s bottleneck. In a graph of interdependent teams, the constraint can sit anywhere in the graph — and improving your own steps produces nothing until it is cleared. Making that visible, with data rather than assumption, is the first move.

Spare capacity at non-constraints

Every step other than the constraint has spare capacity — which is why the steps after the constraint are often idle. This idle time is easily mistaken for inefficiency. The spare capacity is what keeps the constraint supplied and clears its output without becoming a constraint itself.

A developer sitting idle because Review is full isn’t wasting capacity — the process has no throughput to offer them right now. Starting new tickets to fill the time makes the Review pile larger. Work that doesn’t go through the constraint is close to free in throughput terms: refactoring, documentation, improving tooling, helping clear Review — all of these cost the system nothing if the developer doing them isn’t the constraint. The same work placed on the constraint reduces output directly.

Spare capacity at a non-constraint is what protects the constraint and absorbs variation. Removing it does not increase throughput.

The cost of time at the constraint

An hour of the system’s production is equivalent to an hour at the constraint. A day the reviewer is out sick, a release window that gets skipped — each is a loss to the whole system’s output that cannot be recovered. The constraint is already the slowest step running at full capacity; there is no faster reserve to draw on.

  • An hour at the constraint is an hour of output. Gained elsewhere, it is not. Lost at the constraint, it cannot be recovered.
  • The constraint should be kept supplied and free of work a non-constraint step could do.

Little’s Law on the line

Total WIP is shown directly on the board, which lets Little’s Law be verified. Once the line reaches steady state, the product of throughput rate and cycle time equals Total WIP — check it from the readouts: process rate (in /min) ÷ 60 × cycle time (in seconds) ≈ WIP. This holds because WIP = throughput × cycle time for any stable process.

The constraint fixes the completion rate; for a fixed completion rate, cycle time is proportional to WIP. Admitting work faster than the constraint can clear it raises WIP and cycle time without raising output. Keeping WIP near what the constraint can use keeps cycle time low while leaving throughput unchanged.

Takeaways

  • Find the constraint by looking at where work piles up. In most software pipelines it’s Review or Release — the steps with less automation and fewer people relative to the rate of work arriving.
  • Output equals the constraint’s throughput, nothing more. Improving any other step changes local activity, not delivery rate.
  • More developers when Review is the bottleneck makes things worse. More PRs arrive, the queue grows, WIP rises, cycle time rises. Output is unchanged.
  • Admit work at the constraint’s rate. Faster admission only raises WIP and cycle time. Commit to what Review can process.
  • Time at the constraint is the most expensive in the process. A reviewer out for a day costs the whole system a day of output. Protect the constraint from interruption and keep it supplied.
  • Developer idle time when Review is the constraint isn’t waste. Use it on work that doesn’t grow the Review queue — refactoring, tooling, clearing technical debt. The same work at the constraint reduces output directly.