The PR Size Playbook: How Small Should a Pull Request Be?
Review time scales roughly 4x when PR size doubles β which makes size the cheapest lever on your whole delivery pipeline. Where to draw the line, when to split, and the exact numbers to set as a team norm.
Ask a room of engineers how big a pull request should be and you get opinions. Ask them for a number and you get a shrug β which is why PR size ends up being an accident of momentum rather than a team decision. That is expensive, because PR size is the force multiplier behind almost every review-stage metric: review time does not double when PR size doubles. It is closer to 4x.
Above roughly 400 lines, reviewers skim. They catch fewer real defects and defer comments that nobody will address. A ceiling is therefore not a matter of taste β it is the one norm that makes every other number on your review dashboard honest: time to first review, review depth, bounce-backs, merge latency. This post is the playbook: what size to target, how to split without inventing fake commits, and what to do when 400 lines is genuinely not splittable.
Why the ceiling exists β the 4x effect
Review attention is a cognitive budget, and size eats it on two axes at once. First, a 900-line PR takes longer to read per line β big diffs hide their interesting parts. Second, the person who wrote a 900-line diff has held a much longer context than the reviewer who just opened it, so the review conversation happens at an asymmetry of understanding that guarantees bounce-backs. The same change split into three PRs opened on day 1, 3 and 5 merges days earlier than a 900-line monster opened on day 1 β even though the total review work is identical. The batching rule is free throughput.
A size ceiling does not just shorten reviews. It makes the review honest: below the ceiling, someone actually read the diff.
The numbers, by change type
One global ceiling is wrong; size scales with what the change is. Reading aids, not hard limits:
| Change type | Healthy range | Notes |
|---|---|---|
| Docs, comments, formatting | 30β150 lines | Bulk renames are the exception β large but mechanical |
| Config, flags, dependency bumps | 50β200 lines | Review the blast radius, not the diff |
| Routine features and fixes | 100β400 lines | The default case β most PRs should live here |
| Structural changes | Split on intent | An architecture-altering change should never ship as one unit anyway |
Measure your team's median, not anybody's opinion: when the median of routine PRs sits above 400 lines, the whole review system downstream is drowning in diff sizes that nobody can properly read.
How to split: the three cuts that actually work
Cut 1: by seam, not by file count
Split on interfaces, not on arbitrary file boundaries. A data-layer change and its handler wiring are two PRs connected by a thin seam: PR 1 lands the logic, PR 2 lands the wiring. Each PR keeps the diff readable, and CI stays green on each step.
Cut 2: land the types first
When the change is structural, PR 1 is types and interfaces (often review-light), PR 2 is the implementation that fills them. Reviewers read contracts in one pass and implementations in another β and bounce-backs drop because the requirement was already pinned in code both parties read.
Cut 3: feature behind a flag
The unfinished half of a feature does not need to wait in a stale branch: land the completed slice behind a flag, keep the codebase continuously releasable, and delete the flag when the remainder ships. This is also the cut that prevents the "deploy day is Friday" pattern.
When a PR legitimately cannot be cut
Sometimes a 900-line PR is real: a security fix touching every handler, a mechanical rename, a generated migration. The playbook handles it in one line: declare it. A body note β "no review logic here, mechanical change, the interesting part is the first commit" β restores review depth because it tells the reviewer where to spend attention instead of pretending everything deserves equal depth.
For everything else, the split is always available; the blocker is usually intent, not code: nobody wrote down what the change was supposed to do, so splitting has no seams. Write intent first β it is faster than the third bounce-back it prevents.
Making it stick without becoming the PR police
- Track median, not individual PRs. Call out a team-median above 400 at the sprint review, once. Never name a person β a review-stage metric that feels like surveillance loses the trust that makes metrics usable.
- Make the source of splitting a team convention, not a tool-scolding moment: land types first, flags for unfinished halves, intent notes for anything opaque.
- Measure after two weeks and celebrate the drop β PR median and P90 alike. The win is visible in weeks, which is rare enough to make the norm stick.
Curious where your PR size sits next to your review latency? The PR Flow Benchmark is a free report with the healthy ranges and the flag thresholds for six PR flow signals β collected from PR data alone, so it works even if your team does not tag releases.
Conclusion
PR size is not a style debate β it is the cheapest throughput lever available: a 100β400 line routine band, three reliable cuts (land-the-types, feature-flag, split-on-intent), an honest note for the cases that stay big, and a median you track per quarter instead of policing per developer. Adopt the ceiling before you optimize anything else: it makes every other review metric on your dashboard finally readable.
Get the PR Flow Benchmark report
Six PR flow signals benchmarked against healthy small teams β with the flag threshold for each and the one-week fix that moves them.
Download it freeReady to optimize your development process?
Join thousands of developers using DevLyTicks to improve their productivity and code quality.