skip to content

In Flutter, what is the difference between debugDumpApp() and debugDumpRenderTree(), and when would you reach for each?

level: middleimportance: should knowfreq 30%

answer

  1. widgets library vs rendering library
  2. toStringDeep from the root element
  3. size, constraints, relayoutBoundary
  4. w and t in flutter run
  5. never call during build

basics

~20 s

debugDumpApp() prints the widget-level tree from the root element, with dirty flags, dependencies and state; debugDumpRenderTree() prints each render tree with constraints, sizes and parent data. Use the first for what was built, the second for why something has its size.

solid answer

~40 s

`debugDumpApp()` (widgets library) calls `toStringDeep()` on the root element and prints it with `debugPrint`: every widget, including the ones framework `build` methods insert, with details such as `dirty`, inherited `dependencies` and the attached `state`. `debugDumpRenderTree()` (rendering library) prints the tree under each `RenderView`, with `constraints`, `size`, `parentData`, `relayoutBoundary` and the creating widget. I use the widget dump to see what was built and why something rebuilt, and the render dump for layout: constraints go down, sizes come back up. I call them from a callback or press `w` or `t` in `flutter run`, never inside `build()`. They are debug aids; their service extensions exist in debug and profile, not release.

code

dart · 17 lines
dart
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class DumpButtons extends StatelessWidget {
  const DumpButtons({super.key});

  @override
  Widget build(BuildContext context) {
    return const Row(
      children: [
        // Called from a tap, after the frame is built, never from build().
        TextButton(onPressed: debugDumpApp, child: Text('Dump widgets')),
        TextButton(onPressed: debugDumpRenderTree, child: Text('Dump render tree')),
      ],
    );
  }
}

go deeper

for a junior

Recall that debugDumpApp prints widgets and debugDumpRenderTree prints render objects, and that w and t in flutter run trigger them.

for a middle

Explain which fields each dump carries (dirty, dependencies, state versus constraints, size, relayoutBoundary) and why you call them from a callback rather than from build.

for a senior

Show you pick the dump by the question: widget dump for unexpected rebuilds or dependencies, render dump to trace a constraint down to the box that got the wrong size, and debugFillProperties for your own widgets.

for a principal

Consider how text dumps fit bug triage: attached to issues, diffed between states, captured from devices without DevTools, and kept out of release builds.

## Two text dumps, two layers Flutter's layers each have a function that prints their current state to the console through `debugPrint`. Two of them come up in interviews because they answer different questions: | | `debugDumpApp()` | `debugDumpRenderTree()` | |---|---|---| | Library | widgets (`package:flutter/widgets.dart`) | rendering (`package:flutter/rendering.dart`) | | Starts from | the root element (`WidgetsBinding.instance.rootElement`) | every `RenderView` in `RendererBinding.renderViews` | | Prints | widgets as the framework built them | render objects as they were laid out | | Key fields | `dirty`, `dependencies`, `state` | `constraints`, `size`, `parentData`, `relayoutBoundary`, `creator` | | `flutter run` key | `w` ("Dump widget hierarchy") | `t` ("Dump rendering tree") | | Best for | what was built, what is dirty, which inherited widgets it depends on | why a box has its size and position | ## debugDumpApp() The function builds a string with the binding type and build mode on the first line, then calls `toStringDeep()` on the root element, which walks the whole tree. The output includes: - **Every widget, not just yours.** Framework `build` methods insert many widgets you never wrote, such as `_InkFeatures` inside a `Material`. - **State markers.** A line like `TextButton(dirty, dependencies: [MediaQuery, ...], state: _ButtonStyleState#ab76e)` shows that the widget is marked dirty, which inherited widgets it depends on, and its `State`. - **Your own details** if you override `debugFillProperties()` on a custom widget and add `DiagnosticsProperty` objects. It is the text equivalent of the inspector's widget tree with implementation widgets shown, useful in a terminal-only session or to paste into a bug report. ## debugDumpRenderTree() This one prints the render tree of every view. For layout questions it is the more useful dump, because each line carries: - `constraints`, for example `BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)`, the limits the parent handed down; - `size`, what the render object chose within them; - `parentData`, such as the offset a parent assigned; - `relayoutBoundary=upN`, how many ancestors are affected when this object's layout is marked dirty; - `creator`, the widget chain that created the render object. Reading it top to bottom lets you follow a constraint as it is tightened or loosened, for example by a `RenderPadding` that subtracts its insets, until you find where a size went wrong. ## How to call them 1. **From the terminal.** In a `flutter run` session press `w` for the widget hierarchy or `t` for the render tree; `L` dumps the layer tree. 2. **From code.** Call them from a callback, such as a debug button's `onPressed`, after the frame is built. 3. **Not from `build()`.** The docs warn that you cannot call `debugDumpApp()` inside a `build` method while the app is building; the tree is mid-update. ## Build modes The docs describe every `debug...` function as a debug-mode tool. The matching service extensions, which the `w` and `t` keys and DevTools use, are registered when the app is **not** in release mode, so they also answer in profile mode. In release there is no service to call, and diagnostics are trimmed. ## When to use a dump instead of the inspector - You need the whole tree as text to search, diff between two states or attach to an issue. - You are on a remote device or CI log where DevTools is not open. - You want every constraint in one place rather than clicking node by node.

  • In a Flutter render tree dump, what does relayoutBoundary=up3 on a line tell you?
    It says how far layout invalidation spreads: when this render object is marked as needing layout, its three nearest ancestors are marked too, up to the relayout boundary, because its new size might change theirs. A small number means a local relayout; a large one means a change here re-lays out a big part of the screen.
  • How do you make a custom Flutter widget show more detail in debugDumpApp output?
    Override `debugFillProperties(DiagnosticPropertiesBuilder properties)`, call `super`, and add `DiagnosticsProperty` objects (or typed ones such as `IntProperty`). `toStringDeep()` uses those properties to describe the widget, so they appear in the dump and in the inspector's properties tab.

saying these in an interview costs you the question

  • debugDumpApp() prints only the widgets written in your own source files.
  • debugDumpRenderTree() shows widget state and inherited dependencies.
  • Calling debugDumpApp() inside build() is the easiest way to see the current tree.
  • The dump functions return the tree as a value rather than printing it.
  • Both dumps are available from a release build through DevTools.