Flutter Pruner

Flutter Pruner — semantic cleanup for Flutter and Dart projects

pub package pub points CI verified publisher: nhanlee.dev Dart SDK 3.9 or newer tested on Linux, macOS and Windows License

Safety-first semantic cleanup for Dart and Flutter.
Find unreachable declarations and assets, review the evidence, then apply only changes allowed by the configured safety policy.

Flutter Pruner connects Dart declarations, libraries, assets, routes, localization keys, and dependency registrations in one semantic graph. It fails closed when coverage or evidence is incomplete.

Before applying: use a clean Git worktree, review .flutter_pruner/config.yaml, and run apply --dry-run. A scan does not modify project sources or assets, but it does create reports under .flutter_pruner/.

Quick start

Flutter Pruner requires Dart SDK 3.9 or newer.

Install on macOS, Ubuntu, or Windows

dart pub global activate flutter_pruner

If the command is not found, add Pub's executable directory to PATH:

Platform Pub executable directory
macOS / Ubuntu $HOME/.pub-cache/bin
Windows %LOCALAPPDATA%\Pub\Cache\bin

For CI or environments without a global executable:

dart pub global run flutter_pruner:flutter_pruner <command>

Run the safe workflow

From the Flutter or Dart project you want to inspect:

flutter_pruner init
flutter_pruner scan
flutter_pruner apply --dry-run
flutter_pruner apply

init creates the project boundary and target configuration. scan analyzes without changing sources or assets. apply --dry-run shows the eligible plan; only apply can mutate the project.

Use --project path/to/project from another directory. For a disposable first run, follow the complete example.

Read this before applying

  • Start from a clean Git worktree or verified backup. Rollback is a recovery layer, not a replacement for version control.
  • Review the generated configuration. Target coverage is declared by the project owner; Flutter Pruner never infers that every platform, flavor, entrypoint, or Dart define is covered.
  • Treat packages as open world. package mode is audit-only because external consumers are unknown. package-internal deliberately ignores those consumers and requires explicit acknowledgement for eligible HIGH findings.
  • Static analysis has limits. Dynamic strings, custom runtime registries, generated wiring, external deep links, and unresolved references reduce confidence instead of being ignored.
  • Stop on recoveryRequired. Do not run another mutating command until the quarantine and report have been inspected and the project has been recovered.
  • Keep your own backup when metadata matters. Regular-file rollback restores captured bytes and POSIX permissions where available, not ACLs, extended attributes, ownership, or hard-link topology.

See Using Flutter Pruner safely before applying to an important project.

What it finds

Area Detection Apply policy
Dart Unreachable top-level declarations and empty libraries Safety and mode controlled
Assets Assets unreachable from live Dart code Safety and mode controlled
Routes go_router declarations and resolved navigation Review only
Dependency injection Direct base-scope GetIt registrations and lookups Review only
Localization ARB keys and current real-source gen-l10n accessors Review only
Duplicates Byte-identical files grouped with SHA-256 Review only

Member-level Dart deletion, dependency removal, fuzzy image matching, and binary size attribution are outside the current scope.

Understand the result

Tier What it means Eligible for apply?
SAFE Every hard gate passed and no manual risk remains Yes, in application and package-internal modes
HIGH Hard gates passed with exactly one known manual risk Package-internal only, after acknowledgement
REVIEW Evidence is incomplete, ambiguous, or unsupported Never
PROTECTED The item must be kept even if it appears unused Never

PROTECTED always wins. Framework-specific route, GetIt, localization, and duplicate findings remain review-only.

A successful scan exits 0 even when findings exist. CI must inspect the JSON report instead of treating the process exit code as “nothing found”:

flutter_pruner scan --format json --output scan.json

The selected output must not already exist. See the CI selectors for stable checks.

Preview, apply, and recover

To limit a reviewed plan, repeat an exact finding ID:

flutter_pruner apply --dry-run \
  --finding-id 'dart:my_app/lib/example.dart#_unusedHelper'

flutter_pruner apply \
  --finding-id 'dart:my_app/lib/example.dart#_unusedHelper'

The complete selection must remain eligible and dependency-closed; Flutter Pruner does not silently add an unrequested logical finding.

To inspect and restore an applied run:

flutter_pruner quarantine list
flutter_pruner rollback <run-id>

Keep quarantine data until the resulting project has been reviewed and verified. The operational guide explains modes, selection, recovery states, and rollback limits.

Reports

Every completed scan and handled apply outcome saves a unique immutable report. HTML is the default and works offline; JSON v3 is available for CI. The terminal prints the actual committed report path.

Reports can contain absolute project paths, verification step IDs and working directories, toolchain identity, and diagnostics. Review them before sharing.

See structured run reports for storage layout, schema, status, exit codes, compatibility limits, and CI examples.

Upgrade or uninstall

dart pub global activate flutter_pruner
dart pub global deactivate flutter_pruner

Documentation

Using the CLI

Understanding the safety model

Developing Flutter Pruner

Found a false positive or focused feature request? Open an issue. False SAFE findings, data loss, and broken rollback are release-blocking defects.

License

MIT — see LICENSE.

Libraries

flutter_pruner
Semantic auditor for Flutter/Dart projects.