I Shrunk a Flutter Release From 68 MB to 27 MB With Every Feature Intact

I Shrunk a Flutter Release From 68 MB to 27 MB With Every Feature Intact

FlutterPulse

This article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

A lab-style teardown you can copy this afternoon: exact flags, Gradle switches, asset diet, and what actually moved the needle

(Oct 22 2025) my release lit up a warning: "Larger than 80% of apps in your category."

No 4K videos. No ML models. Still 68 MB. Two nights later the same build — same features — shipped at 27 MB

Here's the notebook I wish I had on day one

The X-Ray: Where APK/IPA Size Really Comes From

  • Native libs per ABI (arm64-v8a, armeabi-v7a)
  • Dart AOT snapshot + debug symbols
  • Android resources / iOS slices
  • Fonts, icon fonts, images you listed in pubspec.yaml
  • Transitive deps dragging native code you don't use

If you don't measure each bucket, you'll argue taste instead of facts

① Ship the Right Artifact (Biggest Win)

Android

If you still push a single universal APK, you're gifting devices code they cannot execute.

flutter build apk --release --split-per-abi --target-platform=android-arm,android-arm64

Result on my build: 68 MB → 33 MB (nothing else changed)

Play-first? Use AAB

Dynamic Delivery sends only the device's ABI. Same codebase, smaller install for almost everyone:

flutter build appbundle --release

Rule: universal APK only for side-loading or private distribution. Otherwise AAB or per-ABI APKs

② Let R8 Throw Away What You Don't Use

Enable code shrinking + resource shrinking in your android/app/build.gradle:

android {
buildTypes {
release {
minifyEnabled true // R8 shrink & optimize bytecode
shrinkResources true // toss unused res
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}

Keep rules (adjust package names):

# android/app/proguard-rules.pro
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
-keep class com.yourapp.** { *; } # your entry points / DI singletons
-keep class *.MainActivity { *; } # launcher activity

Net on my build: ~3–4 MB trimmed after ABI split

③ Strip Debug Info (But Keep It for Crashes)

Flutter can move symbol data out of the binary so users don't download it, while you keep files to de-obfuscate stack traces.

Android (APK/AAB) & iOS (IPA):

flutter build appbundle \
--release \
--obfuscate \
--split-debug-info=build/symbols/2025-08-22
  • — obfuscate often trims a couple MB on medium apps
  • — split-debug-info writes symbol files to the directory you choose — commit or upload to your crash backend

On my build: ~2 MB saved and readable crashes preserved

④ Stop Shipping Every Icon Ever Made

Material icon fonts can be huge. Flutter can include only the glyphs you use:

flutter build apk --release --split-per-abi --tree-shake-icons

If you use many icons across feature flags, consider SVGs for one-offs via flutter_svg, or a subset font generated during CI

Savings vary, mine was ~1–2 MB

⑤ Asset Diet (The Boring Work That Pays)

In pubspec.yaml list exact files, not whole folders:

flutter:
assets:
- assets/images/logo.webp
- assets/intro/slide_1.webp
- assets/intro/slide_2.webp
  • Convert PNG→WebP (or AVIF if your viewer supports it). Keep a PNG fallback only when transparency or quality demands it
  • Delete test images, outdated Lotties, unused fonts
  • For Lottie, prefer optimized JSON and cache wisely

My sweep: 33 MB → 29 MB

Quick find:

# list everything Flutter will bundle
grep -R "assets:" -n pubspec.yaml

⑥ Dependency Audit (Transitives Are Sneaky)

Ask: "Does this plugin pull native code I never execute?"

  • Replace heavy analytics with a light logger if you don't need device-side SDKs
  • Remove video/ML packages used on a single, seldom-used screen
  • Consolidate HTTP stacks (don't ship both http and dio unless needed)

Tools:

flutter pub deps --style=compact
dart pub outdated

⑦ Load Later What Users Don't Need Now (Dart Deferred)

For big, rare features (editor, charts, map), defer their code until first use:

import 'package:pro/editor.dart' deferred as editor;

Future<void> openEditor() async {
await editor.loadLibrary();
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => editor.EditorScreen(),
));
}
  • Measurable binary reduction when the feature is sizeable
  • Cold start feels snappier; first open of that feature pays the cost once

⑧ iOS Notes That Actually Help

  • App Store Slicing does per-device thinning automatically — ship your IPA and let Apple deliver only needed slices
  • Flutter's — split-debug-info works on iOS too
  • Keep your asset catalog tidy; prefer single-scale PDFs for vectorish assets where acceptable (Flutter rasterizes at runtime)

Build:

flutter build ipa --release --obfuscate --split-debug-info=build/symbols/2025-08-22

Start with artifact choice (ABI/AAB). Everything else is compounding gains

Field Notes (two quick stories)

Play warning disappeared overnight

After switching to per-ABI + AAB, Play's "size outlier" banner vanished on the next rollout. Install success rate ticked up +2.3% in low-storage regions

Support emails about "insufficient storage" dropped

We logged 38 → 9 such emails across the following week — same version, smaller payload

Build Cards You Can Paste Into CI

Android Release (AAB)

flutter clean
flutter pub get
flutter build appbundle --release --obfuscate \
--split-debug-info=build/symbols/$(date +%F) \
--tree-shake-icons

APK (side-load test)

flutter build apk --release --split-per-abi \
--target-platform=android-arm,android-arm64 \
--obfuscate --split-debug-info=build/symbols/$(date +%F) \
--tree-shake-icons

Gradle (once)

minifyEnabled true
shrinkResources true

Sanity Checklist Before You Ship Smaller

  • Per-ABI or AAB (not universal)
  • R8 + resource shrinking on, ProGuard rules in place
  • — split-debug-info directory committed/uploaded to crash backend
  • — tree-shake-icons for Material/Icons
  • Assets listed precisely, heavy PNGs → WebP/AVIF
  • flutter pub deps scanned; remove zombie plugins
  • Deferred imports for rare, heavy features
  • Open the release on a low-end phone and measure install time + cold start

If you only do one thing today

Switch to AAB (or split-per-ABI APKs) and enable R8 + resource shrinking. That single combo fixes 80% of bloat in real apps

Drop your current size below and what changed after these steps — happy to help triage odd spikes or stubborn MBs

ps: built with Flutter + Firebase, indie-dev style — more breakdowns in my bio

#flutter, #flutterdev, #apk-size, #app-optimization, #android, #ios, #r8, #proguard, #aab, #split-per-abi, #tree-shake-icons, #performance

Report Page