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?
answer
- two size files, same ABI
- the Diff tab: old versus new
- code, assets or native libraries
- dominator tree for the import chain
- upload size is not download size
basics
~20 sBuild 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.
solid answer
~50 sFirst make the comparison fair: build the commit before and after the charts package with identical flags, `flutter build appbundle --analyze-size --target-platform android-arm64`, and keep both `*-code-size-analysis_NN.json` files. Load them as old and new in the DevTools app size tool's **Diff** tab, which shows only what changed. The growth lands in one of three places: **Dart AOT code** from the package and its dependencies, **assets** it bundles such as fonts or images, or **native libraries** from a plugin. For Dart code, the Analysis tab's **dominator tree** on the new file shows which of your imports keeps it alive. Then decide: drop unused package features, pick a lighter package, or move the charts screen into a deferred component on Android. Finally, check the store's per-device download size, because a 60 MB upload bundle carries every ABI and is not what one phone downloads.
code
bash · 10 lines# On the commit before the charts package
flutter build appbundle --analyze-size --target-platform android-arm64
# -> ~/.flutter-devtools/aab-code-size-analysis_01.json
# On the commit after the charts package (same flags, same ABI)
flutter build appbundle --analyze-size --target-platform android-arm64
# -> ~/.flutter-devtools/aab-code-size-analysis_02.json
# Open DevTools, app size tool, Diff tab: _01 as old, _02 as new.
dart devtoolsgo deeper
Know that you measure release builds with --analyze-size and that DevTools can compare two size files.
Explain the Diff tab, why both builds must share flags and ABI, and the three places growth can land.
Drive the investigation to a decision: trace the import with the dominator tree, weigh trim, replace or defer, and confirm with per-device store numbers.
Make dependency additions carry a measured size cost in review, with size files archived per release so growth is always attributable.
## The situation A release app bundle was comfortably small; after one pull request that added a charting package, it is past 60 MB. Two questions follow: **where** exactly did the bytes go, and **is it real** for users or an artifact of how the bundle is packaged? ## Step 1: build a fair pair of size files A diff only means something if both builds differ in nothing but the change. 1. Check out the commit **before** the charts package. 2. Build: `flutter build appbundle --analyze-size --target-platform android-arm64`. Note the file it reports, for example `~/.flutter-devtools/aab-code-size-analysis_01.json`. 3. Check out the commit **after** the change and run the exact same command. The next file gets the next number. 4. Keep both files; they are cheap and make later questions answerable. ## Step 2: diff them Open DevTools, choose the **app size tool**, go to the **Diff** tab, drop the first file into "old" and the second into "new" and click **Analyze Diff**. The treemap and table now show **only data that differs** between the two builds, so a large new rectangle is your answer. | Where the growth shows | Typical cause | Typical fix | |---|---|---| | Dart code under the package's name and its dependencies | a large Dart library pulled in whole | use less of it, or swap for a lighter package | | Assets | bundled fonts, images or data files | remove or compress what you do not use; check if a lighter asset set exists | | Native libraries | a plugin with a native SDK | check whether the native part is needed at all | ## Step 3: find out why the code is kept Load the **new** file in the **Analysis** tab and open the **dominator tree**. Find the package's node and look at what dominates it: often one screen's import. That tells you whether a single feature pulls in everything, and it is also the seam where a deferred component could be cut. ## Step 4: decide what to cut - **Trim**: many chart packages are modular; importing only the chart types you use can shrink the Dart code. - **Replace**: for two simple line charts, a lighter package or a small custom painter may cost far less than a general-purpose library. - **Defer (Android)**: if charts live behind one analytics screen, move that screen's library into a **deferred component** so the base install excludes it. - **Accept**: if the per-device download grew only a little, the right answer may be to keep it and record the cost. ## Step 5: check what users actually download An upload app bundle contains code for every ABI plus content the store strips before delivery. Before treating "60 MB" as the user-facing number, check the per-device download size in the store's size report. The Diff result tells you the relative growth; the store tells you the absolute cost. ## Keep it from happening again Save a size file as a build artifact on every release branch. Then the next "why did we grow?" is a two-minute diff instead of an archaeology project.
- Why must both size files use the same --target-platform?Each analysis covers one ABI's AOT snapshot. Diffing an arm64 build against an arm build would show differences caused by the architecture, not by the charts package, and hide the real change in the noise.
- The Diff shows most growth under a font asset from the charts package; what do you do?Check whether the package actually needs that font for the charts you use, and whether it offers a way to exclude it. If it is an icon font, check whether release builds already trim it before acting; if it is a text font, you may be able to rely on the app's existing fonts instead. Re-diff after the change to confirm the saving.
saying these in an interview costs you the question
- Comparing total file sizes of the two bundles is enough to find the cause.
- A size diff between debug builds is a fair comparison.
- The dominator tree shows which package is the biggest.
- A 60 MB app bundle means each user downloads 60 MB.
- Diffing an arm64 file against an arm file isolates the package's cost.