How to use breakpoints to debug a program (2026)
Quick Answer
To debug with breakpoints, run your program in a debugger, place a breakpoint on a line that runs before the bug appears, then start the program and let it pause there. Inspect variables, step through the code one line or function at a time, and repeat until you find where the program’s actual behaviour diverges from what you expected.
Overview
Breakpoints are one of the safest and fastest ways to understand what a program is really doing at runtime. Instead of guessing from logs or reading code in the abstract, you tell the debugger exactly where to pause execution so you can inspect variables, call stacks and control flow. This is especially useful for logic errors, unexpected values, wrong branches, loops that behave oddly, and crashes that only happen in a specific path. A practical breakpoint workflow is: reproduce the issue, identify the rough area of code involved, set a breakpoint just before the suspected problem, run under the debugger, inspect the current state, then step forward carefully to see where expectations stop matching reality. If needed, add more breakpoints closer to the fault. Good debugging is not just stopping the program; it is comparing the program state with what should have happened at that point. Most modern IDEs and debuggers support basic line breakpoints, conditional breakpoints, watch expressions and stepping controls. The exact buttons differ between tools, but the process is largely the same whether you use Visual Studio, VS Code, IntelliJ IDEA, Eclipse, gdb, lldb or a browser developer tool.
Who this is for
Programmers, students, QA engineers and support engineers who need to diagnose a bug in application code, scripts or browser-based code.
What you’ll need
- The program’s source code
- A debugger or IDE with debugging support
- A way to reproduce the bug consistently
- A build or runtime configuration that includes debug information where applicable
- Basic understanding of the program flow and expected behaviour
Before you start
Make sure you can reproduce the problem reliably enough to test changes in your debugging approach. If the issue only appears in production, try to recreate the same inputs, configuration and environment safely in a development or test setup. Where relevant, use a debug build or ensure symbols/debug information are available, because missing debug information can prevent accurate line-by-line stepping and variable inspection.
Step-by-step
- 1
Reproduce the problem and narrow the area
Run the program normally first and note exactly what goes wrong: the wrong output, an exception, a crash, a hang or a wrong branch being taken. Identify the feature, input or action that triggers it, and narrow the likely part of the code as much as you can before opening the debugger.
Why: A breakpoint is most useful when placed near the fault. If you do not know what triggers the bug, you can waste time pausing in unrelated code.
- 2
Start the program in the debugger
Open the project in your IDE or debugger and launch it in debug mode rather than a normal run. If your tool asks for a launch configuration, choose the correct executable, script, entry point, arguments and environment variables for the failing scenario.
Why: Running under a debugger gives you control over execution and access to runtime state such as variables, threads and the call stack.
- 3
Set a breakpoint before the suspected fault
Click or enter a breakpoint on a line that definitely executes shortly before the bug appears. If you know the exact function involved, place it near the start of that function or just before the suspicious line. If the bug depends on a specific value or iteration, consider a conditional breakpoint so execution only pauses when the relevant condition is true.
Why: Stopping before the failure lets you observe how the state changes into the bad state, instead of only seeing the aftermath.
- 4
Run until the breakpoint is hit
Resume execution and trigger the bug path. When the debugger pauses, confirm that you are in the expected file, function and line. If the breakpoint never hits, check whether the code path is actually reached, whether the source matches the running build, and whether optimisations are interfering.
Why: You must first verify that you are debugging the right code and the right execution path; otherwise any conclusions may be wrong.
- 5
Inspect variables, arguments and the call stack
Look at local variables, function arguments, object properties and any watched expressions relevant to the bug. Check the call stack to see how execution arrived here. Compare the actual values with the values you expected at this point in the program.
Why: Most bugs become visible as a mismatch between expected and actual state, and the call stack shows the chain of decisions that produced that state.
- 6
Step through the code carefully
Use step over to execute the current line without entering called functions, step into to follow a function call in detail, and step out to return from the current function. Move forward one statement at a time around the suspicious area and watch for the moment a variable changes unexpectedly, a condition evaluates differently from expected, or the wrong branch executes.
Why: Stepping isolates the exact instruction or function where behaviour diverges, which is the key to finding the real cause rather than a symptom.
- 7
Refine with additional or conditional breakpoints
If the first breakpoint is too early or too late, remove or disable it and add breakpoints closer to the point of failure. Use conditional breakpoints or logpoints if the code runs many times, such as in loops or event handlers, and you only care about a specific case.
Why: Refining your breakpoints reduces noise and helps you focus on the execution path that actually contains the bug.
- 8
Confirm the fix and retest
After identifying and correcting the issue, run the program again under the same conditions. Check that the breakpoint path now behaves as expected and that the original bug is gone. Then run any relevant automated or manual tests to make sure the fix did not break related behaviour.
Why: A fix is only trustworthy if it resolves the original problem and does not introduce a new one elsewhere.
Why this works
A breakpoint halts execution at a chosen point, turning a fast-moving runtime process into something you can inspect. That lets you compare code, data and control flow at the exact moment the program is making decisions, which is far more reliable than guessing from symptoms alone.
Common mistakes to avoid
- Setting the breakpoint after the bug has already happened
- Debugging a different build or stale binary than the source code you are reading
- Leaving compiler or runtime optimisations on when they make stepping confusing
- Inspecting only one variable and ignoring the call stack or surrounding state
- Using too many breakpoints at once and losing track of the execution path
- Changing code while debugging but not rebuilding or restarting properly
Troubleshooting
The breakpoint never hits
Check that the code path really runs, the program was started in debug mode, the source matches the running build, and debug symbols are available. If relevant, rebuild the project and restart the debugging session.
Variables show as unavailable or incorrect
Use a debug-friendly build or disable optimisations in your development configuration where possible. Some compilers and runtimes optimise away variables or rearrange code.
The program pauses too often in a loop or event handler
Use a conditional breakpoint, hit count, or a breakpoint closer to the exact branch or data case you care about.
Stepping jumps unexpectedly between files or threads
Inspect the call stack and active thread. In asynchronous or multithreaded code, confirm which thread or task you are currently debugging.
The bug disappears under the debugger
This can happen with timing-sensitive or concurrency bugs. Try lighter-touch tools such as logging, tracepoints, race detectors, or reproducing in a controlled test with minimal debugger interference.
Compare your options
Line breakpoint
Best for: General debugging when you know roughly where the problem occurs
Pros: Simple, quick to set, supported almost everywhere
Cons: Can pause too often if the line runs frequently
Conditional breakpoint
Best for: Bugs that only appear for specific values, iterations or object states
Pros: Reduces noise, targets the exact failing case
Cons: Can be slower and requires a clear condition
Watchpoint or data breakpoint
Best for: Finding where a variable or memory location changes unexpectedly
Pros: Excellent for tracking unwanted writes
Cons: Not available in every language or tool, and may have limitations
Logpoint or tracepoint
Best for: Observing flow without fully stopping execution
Pros: Less disruptive, useful when pauses change timing
Cons: Provides less interactive inspection than a true breakpoint
| Option | Best for | Pros | Cons |
|---|---|---|---|
| Line breakpoint | General debugging when you know roughly where the problem occurs | Simple, quick to set, supported almost everywhere | Can pause too often if the line runs frequently |
| Conditional breakpoint | Bugs that only appear for specific values, iterations or object states | Reduces noise, targets the exact failing case | Can be slower and requires a clear condition |
| Watchpoint or data breakpoint | Finding where a variable or memory location changes unexpectedly | Excellent for tracking unwanted writes | Not available in every language or tool, and may have limitations |
| Logpoint or tracepoint | Observing flow without fully stopping execution | Less disruptive, useful when pauses change timing | Provides less interactive inspection than a true breakpoint |
Alternatives
- Add temporary logging or tracing around the suspected code path
- Write a small test that reproduces the bug and debug the test
- Use exception break settings to stop exactly when an error is thrown
- Use profiling or tracing tools for performance-related issues
- Use static analysis or linters to catch likely defects before runtime
Pro tips
- Set the first breakpoint before the failure, not at the visible symptom if possible.
- If a function is called many times, add a condition based on the bad input rather than stepping through every call.
- Use the call stack as often as the variable view; it often explains why the state is wrong.
- Disable breakpoints instead of deleting them if you may need them again shortly.
- When debugging loops, watch the loop counter and the collection size together.
- For asynchronous code, note which thread, task or event callback you are currently in.
Safety notes
- Do not debug directly against live production systems unless your organisation permits it and you understand the operational risk.
- Be careful when inspecting sensitive data such as credentials, personal data or tokens in debugger windows and logs.
- If the program controls hardware, financial transactions or other critical systems, use a safe test environment before stepping through runtime behaviour.
What this guide does not cover: This guide explains the general process for using breakpoints across common debuggers. It does not give button-by-button instructions for a specific IDE, language, framework or operating system.
Cost considerations
Most mainstream IDEs include basic breakpoint debugging, and many command-line debuggers are built into common toolchains. Costs usually arise from paid IDE editions, hosted development environments or the engineering time needed to reproduce complex bugs.
Frequently asked questions
What is the difference between step over and step into?+
Step over runs the current line and pauses at the next line in the same function, without entering any called function. Step into follows the function call so you can debug inside it.
When should I use a conditional breakpoint?+
Use one when a line executes many times but the bug only happens for a specific value, object state or loop iteration. It saves time by pausing only when the relevant condition is met.
Why does my breakpoint appear hollow or disabled?+
That usually means the debugger cannot bind it to running code. Common causes are missing debug symbols, source not matching the build, code that was optimised away, or a breakpoint set on a non-executable line.
Can breakpoints help with crashes?+
Yes. You can set breakpoints before the suspected crash path, and many debuggers can also break when exceptions are thrown or when a fatal signal occurs.
Are breakpoints useful for performance problems?+
Sometimes, but they are usually less suitable than profilers because pausing execution changes timing. For slow code, profiling and tracing tools are often the better first choice.
Sources & references
Guidance on this page is traced to documented sources. Last checked 24 September 2026.
- Microsoft Learn - Debugger feature tour · official
Supports core concepts such as breakpoints, stepping, call stack inspection, variable inspection and general debugger workflow.
- JetBrains IntelliJ IDEA Help - Examine suspended program · manufacturer
Supports the use of breakpoints, stepping, frames, threads and variable inspection in a modern IDE.
The core breakpoint workflow changes slowly, but tool interfaces and exact menu names vary between IDEs and versions.