Flutter Pruner
Safety-first semantic cleanup for Dart and Flutter.
Find unreachable Dart declarations, assets, and other supported resources;
review the evidence, then apply only changes allowed by the configured safety
policy.
📦 Install
Requires Dart SDK 3.9 or newer.
dart pub global activate flutter_pruner
✨ What it finds
Six built-in analyzers share one reachability graph, so cross-domain chains (e.g. a route referencing an asset referenced from Dart) are resolved together:
| Analyzer | Finds |
|---|---|
| 📝 Dart declarations | Unreachable libraries, declarations, unused imports |
| 🖼️ Assets | Declared asset families with no resolved reference |
| 📑 Duplicates | Byte-identical files that could be unified |
| 🧭 GoRouter routes | Routes unreachable from any entry point |
| 💉 GetIt registrations | DI registrations never resolved |
| 🌍 Localization | Unused ARB keys and generated l10n dead code |
Every finding carries a confidence tier and the evidence behind it — the explanation is the product, not a score.
🛡️ Confidence tiers
| Tier | Meaning | Can apply? |
|---|---|---|
SAFE |
Every safety predicate holds | ✅ Yes |
HIGH |
All hard gates hold, one known manual risk | ⚠️ Package-internal only, with confirmation |
REVIEW |
Evidence incomplete or ambiguous | ❌ Never |
PROTECTED |
Must be kept (framework wiring, entry points) | ❌ Never |
PROTECTED always wins. Most findings on a mature codebase land in HIGH or
REVIEW — that is the intended outcome, not a limitation.
🚀 Four commands
flutter_pruner init # declare project boundary and targets
flutter_pruner scan # analyze, save report, change nothing
flutter_pruner apply --dry-run # preview the plan, change nothing
flutter_pruner apply # quarantine originals, mutate, verify
To undo: flutter_pruner rollback <run-id>.
See the 5-minute quickstart for a complete walkthrough.
Choose adapters per run
On an interactive terminal, scan and apply quickly detect applicable
adapters and show a multi-select list. All detected adapters are selected by
default; enter comma-separated numbers or IDs to run only the domains you need.
Automation never prompts. Pass --adapter repeatedly or comma-separate IDs to
make the selection explicit:
flutter_pruner scan --adapter dart,assets
flutter_pruner apply --dry-run --adapter duplicates
🔄 Apply and recover
A mutating run is all-or-nothing: originals are quarantined before editing, the project is rescanned and verified after mutation, and everything is restored if any step fails.
flutter_pruner quarantine list
flutter_pruner quarantine inspect <run-id>
flutter_pruner rollback <run-id>
Read how the workflow works before applying to an important project.
⚠️ Safety in one box
- Start from a clean Git worktree. Rollback is a recovery layer, not a replacement for version control.
- Review
.flutter_pruner/config.yaml. Coverage is declared by you, never inferred. - Scan exits 0 even with findings. Inspect the report, not the exit code.
- Stop on
recoveryRequired. Inspect quarantine before running anything - Interrupting with Ctrl+C is safe. The first signal triggers graceful cleanup; a second signal forces immediate exit. Long operations (analysis, verification) may take 30-60 seconds on large projects. If interrupted during cleanup, the next run will detect the stale lock and provide recovery steps.
- See signal handling and recovery for interruption behavior and stale-lock recovery steps.
📊 Reports
Every completed scan saves one immutable report under
.flutter_pruner/reports/. HTML is the default and works offline — open the
path printed at the end of the run.
For CI, save JSON and inspect tiers — never parse human stdout:
flutter_pruner scan --format json --output scan.json
jq -e '
.run.status == "completed" and
.statistics.findings.byTier.SAFE == 0 and
.statistics.findings.byTier.HIGH == 0
' .flutter_pruner/reports/scan.json
⚙️ Configuration
flutter_pruner init writes .flutter_pruner/config.yaml — the declared
analysis boundary:
version: 1
analysis:
mode: application # application | package | package-internal
target_matrix:
complete: true
targets:
- name: android-prod
platform: android
entrypoint: lib/main.dart
Three modes: application (closed app, SAFE may apply), package
(external consumers unknown, audit-only), package-internal (local package
evaluation, SAFE plus one allowlisted HIGH with confirmation).
See every config field.
📚 Documentation
Technical architecture, report storage, performance, and release-validation notes remain repository-only deep dives.
Found a false SAFE finding, data loss, or broken rollback? Open an
issue — these are
release-blocking defects.
🤝 Contributing
New domains land as adapters in lib/src/adapters/ — see
how to add an adapter.
Core reachability and confidence logic stays domain-agnostic.
📄 License
MIT — see LICENSE.
Libraries
- flutter_pruner
- Semantic auditor for Flutter/Dart projects.