Your Flutter project probably has more dead code than you think.
Dart's analyzer is great at catching type errors. It won't tell you that
lib/features/onboarding/legacy_screen.dart hasn't been imported since March,
or that assets/images/old_logo.png is still in your pubspec but never rendered.
I built fscan to solve this. It's a CLI tool written in Go that performs
static dead-code analysis across your entire Flutter/Dart project.
What it catches
- Unused files — walks the import graph from your entry points, flags orphans
- Unused assets — cross-references pubspec.yaml with actual usage in code
- Unused public API — classes, functions, and widgets with no external callers
- Unused routes — supports auto_route, go_router, and Navigator named routes
- Maybe-unused methods — owner-class-aware matching to minimize false positives
Framework-aware
Flutter requires you to declare build(), initState(), dispose(), and
createState() — but you never call them directly. fscan skips all framework
lifecycle methods and @override annotations.
Generated file handling
.g.dart, .gen.dart, .gr.dart, .freezed.dart files are excluded from
unused-file detection. But they're still read as reference sources — so your
flutter_gen typed accessors and freezed models count as "used."
Owner-class-aware method analysis
A method named load() in BookService is tracked separately from load() in
UserService. No cross-class false positives from common method names.
Same-file self-reference detection
A public method called only within the same file (e.g., called in an event handler
above its declaration) is correctly marked as used.
Install
brew install beobeodev/tap/fscan
# or
npm install -g @beobeodev/fscan
# or
go install github.com/beobeodev/fscan@latest
Run
fscan scan /path/to/your/flutter/project
GitHub: https://github.com/beobeodev/fscan
Two severity levels
- Errors = high confidence, safe to delete
- Warnings = may be intentional (public API, dynamic routing) — review first