Flutter PruneKit — Cut the Dead Weight From Your Flutter Codebase

Flutter PruneKit — Cut the Dead Weight From Your Flutter Codebase

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!🚀

Find unused Dart classes, methods, and extensions — and ship cleaner, faster apps.

📦 Package:pub.dev/packages/flutter_prunekit

Why Your Flutter App Feels Heavier Than It Should

Flutter projects grow fast. What starts as a clean, modular architecture can quickly turn into a jungle of helpers, utilities, and experimental widgets.

Features get prototyped, abandoned, and replaced. Old extensions and data models linger in lib/ long after they've served their purpose.

Before you know it, you're shipping APKs packed with unused code — bloating your builds, confusing new teammates, and slowing down your CI pipeline.

That's where Flutter PruneKit steps in — a focused static analysis tool that hunts down those ghosts in your Dart code.

Why Dead Code Deserves Your Attention

Unused code isn't harmless clutter. It can:

  • Inflate bundle sizes and slow down startup performance.
  • Increase build and test times, stretching feedback loops.
  • Confuse teammates who are trying to understand your system.
  • Conceal bugs when outdated helpers still sit quietly in your source tree.

PruneKit fixes this by giving you an actionable cleanup report — backed by 370+ automated tests and verified on real-world Flutter apps.

Core Capabilities

Flutter PruneKit understands modern Dart semantics:

  • Types: regular and abstract classes, enums, mixins, named/unnamed extensions.
  • Functions: top-level functions, instance/static methods, factory constructors, getters/setters, operators, private methods.
  • Flutter context: automatically preserves lifecycle methods like initState or dispose.

The engine walks the Abstract Syntax Tree (AST) of your project in parallel. That keeps analysis run times short — seconds on medium-sized apps — and minimizes false positives by following override chains, generics, and cross-file extension usage.

Installing PruneKit

Add it to your project as a dev dependency:

dart pub add --dev flutter_prunekit 
dart pub get

Or install globally:

dart pub global activate flutter_prunekit

Your First Scan

dart run flutter_prunekit 
# or, if activated globally:
flutter_prunekit

By default, it scans your lib/ directory and outputs unused declarations grouped by category.

Example output:

═══ Flutter Dead Code Analysis ═══

⚠ Found 5 unused declaration(s):

Classes: 2
Enums: 1

lib/models/old_user.dart:12
OldUser

lib/widgets/legacy_button.dart:8
LegacyButton

lib/utils/deprecated_helper.dart:5
DeprecatedStatus

Top-Level Functions: 1

lib/helpers/formatter.dart:45
formatLegacyData

Instance Methods: 1

UserService (lib/services/user_service.dart:23)
processLegacyUser [instance]

─── Summary ───

Files analyzed: 156
Total declarations: 89
Total methods: 234
Unused: 5
Class usage rate: 96.6%
Method usage rate: 99.1%

Analysis time: 2.3s

Generated Code and Tooling

PruneKit skips generated files by default to avoid misleading results.

If you need to analyze generated code (from Freezed, json_serializable, built_value, Realm, etc.), pass the --include-generated flag:

dart run flutter_prunekit --include-generated

💡 Tip: Run PruneKit both ways — once without generated files to keep noise low, and once with them to catch hidden technical debt.

Known Edge Cases (and Workarounds)

No static analyzer is perfect. PruneKit surfaces potential blind spots:

  • dynamic invocations: when a method call can't be resolved statically, the tool plays it safe and may flag the target as unused. Add @keepUnused annotations or replace dynamic with concrete types when possible.
  • Reflection: mirrored types or runtime lookups need explicit annotations to survive trimming.
  • Conditional imports: platform-specific implementations should be whitelisted manually.
  • Unnamed extensions: Dart's analyzer currently treats any usage as a blanket reference. Name your extensions to maintain precision.

These limitations are rare in pragmatic Flutter apps, but knowing them helps you interpret reports accurately.

Why I Built PruneKit

I built Flutter PruneKit out of necessity.
Working on large Flutter apps, I kept running into the same problem — code that looked important but wasn't used anywhere.

Helpers, mixins, and widgets would survive multiple refactors simply because no one was sure if they were still needed.
Existing tools like linters or IDE inspections caught some of it, but not all — especially across multiple files and abstract layers.

So I started experimenting with a more precise approach — AST-based static analysis that truly understands how Dart works (thanks to AI).
After weeks of iteration, hundreds of tests, and real production trials, PruneKit was born.

If it helps other Flutter teams escape the same dead code anxiety, that's mission accomplished. 🧹

Report Page