
Flutter Dart Code Review
Low Riskby @affaan-mVerified Source
4.3329 installsv1.0.0Updated May 25, 2026
About
Library-agnostic Flutter/Dart code review checklist covering widget best practices, state management patterns (BLoC, Riverpod, Provider, GetX, MobX, Signals), Dart idioms, performance, accessibility, security, and clean architecture.
name: flutter-dart-code-review description: Library-agnostic Flutter/Dart code review checklist covering widget best practices, state management patterns (BLoC, Riverpod, Provider, GetX, MobX, Signals), Dart idioms, performance, accessibility, security, and clean architecture. origin: ECC
Flutter/Dart Code Review Best Practices
Comprehensive, library-agnostic checklist for reviewing Flutter/Dart applications. These principles apply regardless of which state management solution, routing library, or DI framework is used.
1. General Project Health
- [ ] Project follows consistent folder structure (feature-first or layer-first)
- [ ] Proper separation of concerns: UI, business logic, data layers
- [ ] No business logic in widgets; widgets are purely presentational
- [ ]
pubspec.yamlis clean — no unused dependencies, versions pinned appropriately - [ ]
analysis_options.yamlincludes a strict lint set with strict analyzer settings enabled - [ ] No
print()statements in production code — usedart:developerlog()or a logging package - [ ] Generated files (
.g.dart,.freezed.dart,.gr.dart) are up-to-date or in.gitignore - [ ] Platform-specific code isolated behind abstractions
2. Dart Language Pitfalls
- [ ] Implicit dynamic: Missing type annotations leading to
dynamic— enablestrict-casts,strict-inference,strict-raw-types - [ ] Null safety misuse: Excessive
!(bang operator) instead of proper null checks or Dart 3 pattern matching (if (value case var v?)) - [ ] Type promotion failures: Using
this.fieldwhere local variable promotion would work - [ ] Catching too broadly:
catch (e)withoutonclause; always specify exception types - [ ] Catching
Error:Errorsubtypes indicate bugs and should not be caught - [ ] Unused
async: Functions markedasyncthat neverawait— unnecessary overhead - [ ]
lateoveruse:lateused where nullable or constructor initialization would be safer; defers errors to runtime - [ ] String concatenation in loops: Use
StringBufferinstead of+for iterative string building - [ ] Mutable state in
constcontexts: Fields inconstconstructor classes should not be mutable - [ ] Ignoring
Futurereturn values: Useawaitor explicitly callunawaited()to signal intent - [ ]
varwherefinalworks: Preferfinalfor locals andconstfor compile-time constants - [ ] Relative imports: Use
package:imports for consistency - [ ] Mutable collections exposed: Public APIs should return unmodifiable views, not raw
List/Map - [ ] Missing Dart 3 pattern matching: Prefer switch expressions and
if-caseover verboseischecks and manual casting - [ ] Throwaway classes for multiple returns: Use Dart 3 records
(String, int)instead of single-use DTOs - [ ]
print()in production code: Usedart:developerlog()or the project's logging package;print()has no log levels and cannot be filtered
3. Widget Best Practices
Widget decomposition:
- [ ] No single widget with a
build()method exceeding ~80-100 lines - [ ] Widgets split by encapsulation AND by how they change (rebuild boundaries)
- [ ] Private
_build*()helper methods that return widgets are extracted to separate widget classes (enables element reuse, const propagation, and framework optimizations) - [ ] Stateless widgets preferred over Stateful where no mutable local state is needed
- [ ] Extracted widgets are in separate files when reusable
Const usage:
- [ ]
constconstructors used wherever possible — prevents unnecessary rebuilds - [ ]
constliterals for collections that don't change (const [],const {}) - [ ] Constructor is declared
constwhen all fields are final
Key usage:
- [ ]
ValueKeyused in lists/grids to preserve state across reorders - [ ]
GlobalKeyused sparingly — only when accessing state across the tree is truly needed - [ ]
UniqueKeyavoided inbuild()— it forces rebuild every frame - [ ]
ObjectKeyused when identity is based on a data object rather than a single value
Theming & design system:
- [ ] Colors come from
Theme.of(context).colorScheme— no hardcodedColors.redor hex values - [ ] Text styles come from
Theme.of(context).textTheme— no inlineTextStylewith raw font sizes - [ ] Dark mode compatibility verified — no assumptions about light background
- [ ] Spacing and sizing use consistent design tokens or constants, not magic numbers
Build method complexity:
- [ ] No network calls, file I/O, or heavy computation in
build() - [ ] No
Future.then()orasyncwork inbuild() - [ ] No subscription creation (
.listen()) inbuild() - [ ]
setState()localized to smallest possible subtree
4. State Management (Library-Agnostic)
These principles apply to all Flutter state management solutions (BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier, etc.).
Arch
Compatible Tools
Claude CodeCursor
Tags
Mobile
