When production breaks, the pressure pushes people toward guessing: change something, deploy, hope. Sometimes it works. Often it creates a second problem, and the original one comes back next week.
Fast debugging is not about typing faster or knowing every tool. It is about a disciplined process that narrows the search space quickly. This is the process I use when I am called in to find the cause of a production issue.
1. Stabilise before you investigate
If users are actively affected, the first job is to limit damage, not to find the root cause:
- Roll back the latest deployment if the timing matches.
- Turn off the feature behind a feature flag.
- Scale up or restart if resources are exhausted — while capturing evidence first (logs, heap dumps, metrics screenshots).
Mitigation buys time to investigate properly. Just make sure it does not destroy the evidence you will need.
2. Define the problem precisely
"Checkout is broken" is not a problem statement. Before looking at code, get answers to:
- What exactly happens? Error message, screenshot, blank screen, wrong data, slowness?
- Who is affected? All users, or a segment — one browser, one country, one account type, one app version?
- Since when? The first occurrence is one of the most valuable clues you have.
- How often? Every time, or intermittently?
- What changed around that time? Deployments, configuration, feature flags, third-party services, data migrations, traffic spikes, certificate expiry.
A precise problem statement often halves the investigation. "Since Tuesday's release, Safari users on iOS 17 get a blank checkout page after applying a coupon" points you directly at a small area.
3. Gather evidence from the right places
Look at data before forming theories:
- Error tracking (Sentry, Rollbar, Bugsnag, etc.) — stack traces, affected releases, browsers, breadcrumbs of what the user did.
- Application logs — ideally structured (JSON) with a request or correlation ID that follows a request across frontend, API and services.
- Metrics and dashboards — error rates, latency, CPU, memory, database connections. Look for the moment the graph changed.
- Network activity — for frontend issues, the failing request, its status code, payload and response are often the whole answer.
- Deployment and change history — what shipped, what configuration changed, which dependency was upgraded.
If you do not have these, the first improvement after this incident is to add them. You cannot debug efficiently what you cannot observe.
4. Reproduce it
A reproducible bug is usually a solvable bug. Try to recreate the exact conditions:
- Same browser, device, app version and user role.
- Same data — many "impossible" bugs come from unexpected production data: nulls, very long strings, special characters, old records created before a schema change.
- Same environment settings — feature flags, locale, time zone, network speed.
If it only happens in production, ask why production is different. The answer to that question is frequently the root cause.
For intermittent issues, look for patterns in the evidence rather than trying to reproduce by luck: time of day, load, specific users, concurrent actions, or cache state.
5. Narrow the search space systematically
Once you can reproduce the problem, stop reading code top to bottom and bisect:
- In time:
git bisectbetween the last known good and first known bad release finds the exact commit, often in a handful of steps. - In the stack: is the data wrong in the database, in the API response, or only in the UI? Check each boundary. The bug is between the last correct value and the first wrong one.
- In the code path: comment out, stub or bypass halves of the suspected logic until the symptom disappears.
Every check should cut the remaining possibilities roughly in half. That is what makes debugging fast.
6. Form a hypothesis — and try to prove it wrong
When you have a candidate explanation, state it precisely: "The coupon endpoint returns discount: null for percentage coupons, and the Safari build throws when formatting null." Then look for evidence that would disprove it. If the explanation predicts the bug should also happen for other users and it does not, the explanation is incomplete.
Confirmation bias is the main reason debugging goes in circles. A good hypothesis explains all the observed facts, including who is not affected.
7. Find the root cause, not just the trigger
The line that throws is rarely the whole story. Ask "why?" until you reach something you can prevent:
- Why did the page crash? — The formatter received null.
- Why was it null? — The API changed its response for one coupon type.
- Why did that reach production? — There was no contract test between frontend and API.
- Why was it not caught in monitoring? — Errors from that page were not being reported.
The fix for the symptom might be a null check. The fix for the root cause might be a typed API contract and an alert. Both matter.
8. Fix safely and verify
- Write a failing test that reproduces the bug before fixing it, where practical.
- Make the smallest change that fixes the root cause; larger clean-ups can follow separately.
- Deploy with monitoring in place and confirm the error rate returns to normal — do not assume.
9. Close the loop
A short, blameless write-up turns one incident into lasting improvement:
- What happened and what the impact was.
- The timeline from first signal to resolution.
- The root cause and contributing factors.
- The actions that prevent recurrence — tests, alerts, validation, documentation.
Frontend-specific checklist
Frontend production bugs have their own common causes. Check these early:
- Browser-specific behaviour (Safari date parsing, CSS support, private-mode storage restrictions).
- Stale caches or service workers serving old bundles with new APIs.
- Chunk-loading failures after a deployment removes old files users still reference.
- Race conditions between parallel requests, or state updated after a component unmounts.
- Third-party scripts — analytics, chat widgets, tag managers — modifying the page or throwing errors.
- Content Security Policy or CORS changes blocking requests.
- Time zone and locale differences in date and number formatting.
Make the next incident faster
The fastest debugging happens in systems designed to be debugged: error tracking with source maps, structured logs with correlation IDs, meaningful dashboards, feature flags and fast rollbacks. Investing in these after one painful incident is one of the best returns a team can get.
If you have a production issue that has resisted your team's attempts to fix it, or a system that keeps having "random" problems, an outside, structured investigation often finds the cause faster than another round of guessing.