Reviewing a deletion-heavy pull request takes about 20 to 40 minutes done properly. You read the PR description first, trace every removed symbol to either a replacement or a confirmed dead end, check that no safety nets left with the feature, validate callers, run or mentally walk the affected path, then write a comment the author can act on.
Most developers spend that time on additions. Deletions feel like cleanup, so they get a lighter pass. That's where regressions hide: a removed middleware check, a vanished test, an exported function that two other services still import.
The steps below follow the order that matters. Skip one and you'll likely miss the class of bug it was designed to catch.
1. Understand what the deletion is actually doing
Before reading a single line of diff, establish the category: dead code removal, logic consolidation, or feature deletion. Each carries different risks, and the category shapes how hard you scrutinize every removed line.
Open the PR description first. A good author explains the why. If the description is thin, check the linked ticket or commit message before you touch the diff. You're looking for one thing: the stated reason the code no longer needs to exist.
Ask yourself whether this deletion is safe to reverse if production breaks. A feature flag removal that goes out with a one-way data migration is not safe to roll back. A dead utility function almost certainly is. That answer determines how much scrutiny the rest of your pull request review deserves.
Confirm the scope, too. One deleted file is a different review from fifty lines scattered across a service layer.
2. Check that every deletion has a reason traceable to the diff
Every removed line should map to something visible in the PR: a refactor, a dependency removal, a renamed function, or a killed feature flag. If you can't trace a deletion back to an intention, that's your first comment.
2a. Map deletions to their replacements
A deletion with no corresponding addition anywhere in the diff is the most dangerous pattern. Search the codebase for the symbol, route, or export that just disappeared and confirm it's no longer called anywhere. GitHub's global search and git grep are both fast for this.
2b. Verify dead-code claims
If the author says the code is unreachable, check the call graph yourself. IDE tooling like Find Usages in VS Code or IntelliJ will surface callers the author may have missed, including dynamic calls through reflection or string-based routing. Don't take "nobody calls this" on faith. It takes under a minute to verify, and it's wrong often enough to be worth checking every time.
3. Look for deleted safety nets
Deleted code frequently takes its guardrails with it. Validators, middleware, error handlers, and rate limiters sit close to the feature being removed, so they disappear in the same commit without anyone noticing.
Scan specifically for deleted conditional checks. An if (!user.isAdmin) block that disappears alongside a feature can silently open a privilege-escalation path if the route stays live. The feature is gone; the endpoint sometimes isn't.
Check for deleted tests. If a test file shrinks or vanishes entirely, confirm the behaviour it covered is either gone from the product or tested elsewhere. A deletion that drops test coverage without dropping the feature is a bug with a slow fuse.
Look at deleted logging and monitoring calls as well. A removed metrics hook won't cause a crash today, but it will blind the on-call engineer when something related goes wrong next month. For a deeper look at what gets missed when observability code changes hands, reviewing pull requests that touch logging is worth its own pass.
4. Validate the impact on dependents
A deletion that looks clean inside one module can break callers in another service, a mobile client, or a third-party integration. Internal cleanliness is not the same as external safety.
4a. Check internal callers
Search the repository for every import, require, or use of the deleted symbol. If the codebase uses TypeScript or another typed language, a clean build after the change is a strong signal, but not a guarantee. Dynamic imports and eval-style calls won't surface in type checking. Look for those patterns before you approve.
4b. Check external contracts
If the deleted code touches a public API, an event schema, or a shared database table, flag it for a breaking-change review. A deleted JSON field that a downstream consumer reads will not throw an error in this repo's test suite. It will throw an error in production, reported by a user. The same logic applies to deleted webhook payloads and removed columns that a reporting tool queries directly. If you're unsure how to approach a PR that also introduces or removes external integrations, reviewing new external API integrations covers the overlapping concerns.
5. Run the PR locally or trace it mentally
Approving a deletion without tracing the execution path is the most common way reviewers miss a regression. You have two options: run the code or walk it.
Check out the branch and run the affected tests. If the suite passes but you removed a branch of logic, write a test for the behaviour that's gone and confirm it either passes (because the feature was genuinely dead) or that you've documented the intended loss of behaviour. A failing test you write yourself is a useful artefact for the PR thread.
If you can't run the code, walk through the call chain from the entry point down. Narrate it in a comment if it helps. That narration often surfaces the gap you would have approved past.
When this step is done, you'll have one of three things: a green test run, a failing test you've flagged, or a written trace in your review comment the author can verify.
6. Write your review comment so the author can act on it
A review comment on a deletion should name the specific line or symbol, state the risk plainly, and suggest a concrete next step. Flagging that something "looks off" is not a review comment; it's a worry.
Use GitHub's suggestion blocks for small fixes. For larger concerns, open a numbered list in your comment so the author knows exactly how many issues need resolving before you'll approve.
If you're confident the deletion is safe after your checks, say so explicitly. "Deletion looks clean, callers confirmed, tests updated" is more useful than a bare approval tick because it tells the next reviewer what you actually verified. What makes a review comment actionable rather than just correct goes into the mechanics of this in more detail.
One honest note: reviewing your own PR is possible on most platforms, but it defeats the purpose. You can leave a self-review comment explaining what you checked before asking a teammate for another pass, and that's worth doing, but it's not a substitute for a second pair of eyes.
Frequently asked questions
How do I request a pull request review on GitHub?
On GitHub, open the PR and find the "Reviewers" section in the right-hand sidebar. Click the gear icon, type a teammate's username, and select them. They'll receive a notification. You can also request a review from a team rather than an individual if your repository has teams configured.
What are the best practices for reviewing pull requests?
Read the PR description before the diff, limit each review session to a manageable scope, comment on behaviour rather than style where possible, and distinguish between blocking concerns and optional suggestions. GitHub pull request best practices worth following covers which conventions hold up and which ones don't.
Can I review my own pull request?
You can, and it's worth doing as a final self-check before requesting a teammate's review. Read your own diff 24 hours later if you can. You'll catch things you glossed over when you wrote them. But self-review doesn't satisfy a required reviewer gate on most platforms, and it shouldn't: you can't reliably spot your own blind spots.
Try a graded deletion-heavy review on Goodcatch and see exactly what you catch and what you miss.