skip to content

Binary Footprint & Startup

Download size comes from AOT code, assets and the engine, and startup from the time to the first frame. Interviewers ask how you measured each one and what you split, deferred or removed.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

5

In Flutter, how do you measure what makes up a release app's size, and why are debug builds and upload packages misleading?

level: middleimportance: must knowfreq 48%

answer

  1. release builds only
  2. one Android ABI at a time
  3. a code-size-analysis JSON file
  4. treemap, dominator tree, call graph
  5. stores split the upload package

basics

~20 s

Build a release with --analyze-size (one ABI on Android), read the terminal summary, then open the generated code-size-analysis JSON in the DevTools app size tool. Debug builds carry JIT overhead, and upload packages hold content the stores strip per device.

solid answer

~40 s

Run a release build with `--analyze-size`, for example `flutter build apk --analyze-size --target-platform android-arm64`; it works for `apk`, `appbundle`, `ios`, `macos`, `windows` and `linux`, refuses non-release builds and multiple Android ABIs, and cannot be combined with `--split-debug-info`. The tool prints a summary by category (assets, native code, Dart AOT code per package) and writes a `*-code-size-analysis_NN.json` file under `~/.flutter-devtools/`, with the `dart devtools --appSizeBase=...` command to open it. In the DevTools app size tool the treemap shows where bytes go and the dominator tree shows why code is kept. Debug builds are JIT builds with hot-reload overhead, so their size means nothing; and an APK, app bundle or iOS archive is an upload package the stores reprocess per device, so use the stores' own reports for real download size.

code

bash · 7 lines
bash
# Release build for one Android ABI, with a size breakdown.
flutter build appbundle --analyze-size --target-platform android-arm64

# The tool prints where it wrote the analysis file, for example:
#   ~/.flutter-devtools/aab-code-size-analysis_01.json
# and the command to open it:
dart devtools --appSizeBase=$HOME/.flutter-devtools/aab-code-size-analysis_01.json

go deeper

for a junior

Know that debug builds are not representative and that --analyze-size on a release build gives the real breakdown.

for a middle

Explain the parts of an app's size, the flag's constraints (release, one Android ABI, no split-debug-info) and how to open the file in DevTools.

for a senior

Separate upload-package size from per-device download size, and use the dominator tree to trace growth back to the import that caused it.

for a principal

Turn size into a tracked number per release, with the analysis file kept as an artifact so any growth can be diffed and owned.

## What makes up a Flutter app's size A release Flutter app is self-contained. Its size comes from a few distinct parts: - **Dart AOT code**: your code and every Dart package, compiled ahead of time into a native library (on Android, `libapp.so`). - **The Flutter engine**: the renderer and runtime (on Android, `libflutter.so`). - **Assets**: images, fonts, JSON and anything else listed in `pubspec.yaml`, including assets packages bring along. - **Native plugin code**: Kotlin, Java, Swift or Objective-C code and any native SDKs your plugins pull in. Size questions start with finding which of these grew. ## Why the easy numbers mislead | Artifact | Why it misleads | |---|---| | Debug build from `flutter run` | JIT-compiled with hot reload and debugging support; far larger than release | | `flutter build apk` or `appbundle` output | An **upload package**: may hold several ABIs and every asset density; the store splits it per device | | iOS `.app` from `--analyze-size` | Useful for relative breakdowns; not the downloaded IPA | The Flutter docs send you to the stores' own reports for the real figure: the Play Console's app size view for Android and Xcode's App Thinning Size Report (or App Store Connect) for iOS. ## Breaking the size down with --analyze-size 1. **Build release with the flag**, for example `flutter build appbundle --analyze-size --target-platform android-arm64`. Supported on `apk`, `appbundle`, `ios`, `macos`, `windows` and `linux`, not on `web`. 2. **Respect its constraints.** The tool exits with `"--analyze-size" can only be used on release builds.`, refuses Android builds for more than one ABI ("Cannot perform code size analysis when building for multiple ABIs"), and cannot be combined with `--split-debug-info`. On iOS only arm64 symbols are analyzed. 3. **Read the terminal summary.** It breaks the package into categories (assets, native libraries, Dart code) and splits the Dart AOT library by package. 4. **Find the JSON.** The tool writes `apk-code-size-analysis_01.json` (or `aab-`, `ios-`, `macos-` and so on) under `~/.flutter-devtools/` and prints `dart devtools --appSizeBase=<file>`. Intermediate files go under the build directory unless you set `--code-size-directory`. ## Reading it in DevTools The **app size tool** has two tabs: - **Analysis**: one size file. The **treemap** and table show where bytes go, down to individual functions in the Dart AOT artifact. The **dominator tree** answers "which import is the root reason this code is here?", and the **call graph** shows every path to a piece of code. - **Diff**: an old and a new size file from the same app, showing only what changed, the tool for "what grew in this release?". ## What to do with the answer - Large **assets**: compress images, drop unused files and resolutions. - Large **Dart packages**: use the dominator tree to see which of your imports keeps them, then replace or trim. - Large **native code**: check which plugin brings a native SDK. - Platform-only code: guard it with `Platform.isWindows`-style checks so the compiler drops it from other targets.

  • Why does flutter build apk --analyze-size fail without --target-platform?
    A default APK build targets several ABIs, and the size analyzer works on one AOT snapshot at a time. The tool exits with 'Cannot perform code size analysis when building for multiple ABIs' and asks for one of `android-arm`, `android-arm64` or `android-x64`. Pick the ABI most of your users run, usually `android-arm64`.
  • In the DevTools app size tool, when do you use the dominator tree instead of the treemap?
    The treemap tells you what is big. The dominator tree tells you why it is there: it shows, for a package or function, the node every path to it goes through, often one import in one of your files. That is what you change to remove it.

saying these in an interview costs you the question

  • The size of a debug APK is close to what users download.
  • The app bundle's file size equals the Play Store download size.
  • --analyze-size works on any build mode, including debug.
  • --analyze-size can analyze all Android ABIs in one build.
  • Assets never show up in the analysis because it only covers Dart code.
open as a page

In Flutter, how do you measure the time to first frame with flutter run --trace-startup, and what does it report?

level: juniorimportance: should knowfreq 26%

basics

~20 s

Run flutter run --profile --trace-startup: the tool records startup, prints 'Time to first frame', writes start_up_info.json to the build directory and exits. It measures from the engine's entry point to the first frame built and rasterized.

open as a page

A Flutter app bundle grew past 60 MB right after adding a charts package; how do you find exactly what grew and decide what to cut?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Build release size files before and after the change with the same flags and ABI, load both into the DevTools Diff tab, see whether Dart code, assets or native libraries grew, trace the cause with the dominator tree, then trim, replace or defer it.

open as a page

A Flutter app keeps its launch screen up for three seconds before the first frame; how do you find and cut what delays it?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Trace startup in profile mode; if most time falls after framework init, the delay is your code. Profile the AppStartUp user tag, then shrink what main() awaits before runApp, run it in parallel, and postpone non-critical setup until after the first frame.

open as a page

In Flutter on Android, how do deferred components with loadLibrary() reduce the initial download, and what setup do they need?

level: seniorimportance: nice to knowfreq 16%

basics

~20 s

Deferred components split Dart code and assets into Android dynamic feature modules that download at runtime when loadLibrary() is called. They need deferred imports, a deferred-components section in pubspec.yaml, Play Store split support and flutter build appbundle.

open as a page