tezvyn:

Tree Shaking Removes Unused Flutter Code

AI-drafted, machine-checkedintermediate

Tree shaking is the compiler deleting code your app never calls, so importing a massive package only costs the pieces you use. It runs automatically in release builds. Relying on dynamic dispatch or dart:mirrors silently disables it and brings back the bloat.

WHY IT EXISTS: Flutter apps compile to machine code or JavaScript, and every unused class or function increases binary size and startup time. Before tree shaking, importing a large package meant embedding the entire package even if you only called one helper method. The goal is to ship only the code that actually runs, keeping mobile bundles under store size limits and web bundles small enough to cache quickly.

THE MENTAL MODEL: Think of tree shaking like packing a suitcase by starting with your itinerary instead of your closet. You do not fold and pack every shirt you own; you only pack the outfits the itinerary demands. The compiler starts at the main entry point and walks every possible call path. Anything it cannot reach stays behind.

HOW IT WORKS: During a release build, the Dart compiler performs whole-program analysis starting from main. It marks every function, class, field, and constant that is statically reachable. Unmarked code is discarded. This applies across package boundaries, so a dependency with thousands of icons or utility classes contributes almost nothing if you only import one. The process relies on static typing; if the compiler can prove a call site targets a specific method, it keeps that method. Indirection through dynamic types hides those edges and forces the compiler to keep more code.

WHEN TO USE IT: You rely on tree shaking in every release build, but you actively leverage it when choosing large dependencies. Using a full icon pack or an internationalization library is safe because only the locales and icons you reference survive compilation. You also design for it by preferring const constructors and static methods over runtime registration patterns that obscure the call graph.

WHEN NOT TO USE IT: Tree shaking fails when code is reached through paths the compiler cannot see. Using dynamic dispatch, dart:mirrors, or noSuchMethod tricks breaks the static call graph. Similarly, runtime service locators that map strings to types prevent the compiler from knowing which constructors are alive. If your architecture depends on reflective registration, you defeat tree shaking and pay the full size cost.

ONE CANONICAL EXAMPLE: Suppose you import the Material Icons font for Flutter web but only display the menu and close glyphs. Without tree shaking, the browser downloads the entire multi-hundred-kilobyte font file. With font tree shaking enabled in release builds, the compiler subsets the font to just those two glyphs, often dropping the payload below ten kilobytes. The same principle applies to Dart code: importing a charts library for a single pie chart does not bloat your app with bar-chart renderers.

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.