In Flutter, how do you set breakpoints and step through code with the DevTools debugger, and what does dart:developer's debugger() add?
answer
- click the line-number gutter
- step in, step over, step out
- call stack and variables of the paused isolate
- break on unhandled or all exceptions
- debugger(when:) returns its condition
basics
~20 sClick the line-number gutter in the DevTools Debugger or your IDE to set a breakpoint, then read the call stack and variables and step in, over or out. dart:developer's debugger(when: condition) is a code-level breakpoint that pauses only when true.
solid answer
~40 sIn the DevTools **Debugger** tab (hidden when the app was launched from VS Code, which has its own), I open a file via **Libraries** or Ctrl/Cmd+P and click the gutter to set a breakpoint. When the isolate pauses, the **Call stack** and **Variables** panes fill in; selecting a frame shows its locals, and hovering an object shows its `toString()`. **Step in** enters the called method, **Step over** runs it and stops on the next line, **Step out** finishes the current method, and **Resume** continues. The **Ignore** dropdown chooses whether to break on unhandled exceptions or on all exceptions. `debugger(when: cond, message: ...)` from `dart:developer` is a breakpoint in code that pauses only when `cond` is true and returns it. Hot restart clears user breakpoints, and a stray `debugger()` call must not ship.
code
dart · 12 linesimport 'dart:developer';
import 'package:flutter/foundation.dart';
int cartTotalCents(List<int> lineCents, int discountCents) {
final int total = lineCents.fold(0, (sum, c) => sum + c) - discountCents;
if (kDebugMode) {
// Pauses like a breakpoint only when the bug condition holds.
debugger(when: total < 0, message: 'negative total: $total');
}
return total;
}go deeper
Know how to set a breakpoint, read the call stack and variables, and use step in, step over, step out and resume.
Explain the exception modes, how debugger(when:) works as a code-level conditional breakpoint, and why hot restart clears DevTools breakpoints.
Show you choose between logging, conditional breakpoints and break-on-all-exceptions depending on the bug, and that you never leave debugger() calls in shipped code.
Consider debuggability as a property of the codebase: small functions with clear call stacks, errors surfaced rather than swallowed, and debug-only hooks guarded consistently.
## Where breakpoints live Flutter apps are debugged through the **Dart VM service**, the debugging protocol that the Dart runtime exposes in debug and profile builds. Two front ends use it: - your **IDE's debugger** (VS Code, Android Studio, IntelliJ), which most people use day to day; - the **Debugger** tab in DevTools, a full source-level debugger. DevTools hides this tab when the app was launched from VS Code, because VS Code has its own. Both support breakpoints, stepping and variable inspection. ## Setting a breakpoint in DevTools 1. Open the Debugger tab; the app's main entry point is shown. 2. Click **Libraries**, or press Ctrl/Cmd+P, to find another source file. 3. Click the **line-number gutter** to add a breakpoint; it appears in the **Breakpoints** list. Click again to remove it. 4. Trigger the code. The isolate pauses at the breakpoint and the source view highlights the line. ## Reading the paused state - **Call stack**: the frames of the paused isolate. Selecting a frame switches the variables pane to that frame. - **Variables**: the locals of the selected frame; expand objects to see their fields, hover to see `toString()`. - **Console**: the app's stdout and stderr, also visible in the Logging view. ## Stepping | Button | Effect | |---|---| | **Step in** | enter the method call on this line and stop at its first executable line | | **Step over** | run the call and stop on the next line of the current method | | **Step out** | run to the end of the current method without stopping at intermediate lines | | **Resume** | continue normal execution until the next breakpoint | ## Breaking on exceptions The **Ignore** dropdown at the top of the debugger sets the exception mode: - break on **unhandled** exceptions, which pauses only when application code does not catch the exception; - break on **all** exceptions, which pauses whether or not the code catches it, useful when a `try`/`catch` swallows the error you are hunting. ## debugger() from dart:developer `debugger({bool when = true, String? message})` is a **programmatic breakpoint**. If `when` is true, the program stops as if a breakpoint were hit on the next statement, and the function returns the value of `when`. Some debuggers show `message`. It is useful when the interesting condition is easier to express in code than in an IDE's conditional-breakpoint dialog, for example `debugger(when: total < 0)` inside a price calculation. Two cautions from its documentation and from experience: - The SDK notes that once `debugger()` fires, the isolate does not return until a debugger continues execution, and that in the Dart VM this is the same whether or not a debugger is connected. A forgotten call is therefore not harmless: remove it before committing, or guard it with `kDebugMode`. - Compiled to JavaScript, it becomes the JavaScript `debugger` statement. ## Known pitfall A **hot restart clears user breakpoints** in the DevTools debugger, a documented known issue, so after a restart you set them again.
- In Flutter debugging, when would you switch the exception mode from unhandled to all exceptions?When an error is caught and swallowed somewhere, for example by a `try`/`catch` that logs and continues or a library that converts it into a return value. Breaking on unhandled exceptions never pauses there, while breaking on all exceptions stops at the throw site so you can see the original stack and state.
- Why did your DevTools breakpoints disappear after a hot restart of the Flutter app?The DevTools debugger documents this as a known issue: a hot restart clears user breakpoints, since it re-creates the app's program state. Set them again after restarting, or keep breakpoints in the IDE, which manages its own list.
saying these in an interview costs you the question
- Breakpoints only work in release builds, where code runs at full speed.
- Step over skips the called method without running it.
- debugger() is a no-op unless DevTools is open.
- Breaking on unhandled exceptions also stops inside caught exceptions.
- Hot restart keeps every DevTools breakpoint in place.