Let Kody automatically check quality, security and performance in every pull request—cloud or self-hosted, in under 2 minutes.
Check every pull request with this Flutter code review checklist to keep your app’s code clean, secure and performing well before production.
Here’s what this checklist helps you review before approving a pull request.
✅ Code & UI Quality – Dart style & readability, null-safety, clean widget composition, and solid state management
✅ Security & Performance – safe data handling, async/concurrency control, efficient rendering and memory use
✅ Operational Readiness – robust error handling, testing strategy, observability, CI/CD and safe rollouts
✅ Integration & Data – navigation & deep links, i18n/l10n, theming, APIs/networking, data persistence and migrations
Use these points as a starting guide to automate code reviews with your agent.
Names are precise, intention-revealing, consistent (files/dirs snake_case
; classes/types PascalCase
; members camelCase
).
Public APIs documented with ///
; comments explain why, not what; no commented-out code.
Files are cohesive (one main responsibility); avoid “god” widgets/files.
Limit nesting; extract widgets/helpers; keep methods short; prefer early returns.
No magic numbers/strings—use constants/enums.
const
everywhere possible (constructors/widgets).
Imports are ordered; no unused imports; relative vs package imports are consistent.
Formatting and lints pass; no // ignore:
without justification.
Strict null safety: no !
unless validated; prefer type-narrowing/guards.
Avoid dynamic
; prefer precise types; var
only when obvious.
Use final
for immutability by default; prefer unmodifiable
views for collections.
Prefer sealed
, base
, interface
classes where applicable; exhaustive switch
.
Use enum
with extension methods for behavior; avoid boolean flags—use sealed states/options.
Extension methods scoped appropriately; avoid polluting core types.
Widgets are small, composable, side-effect free; avoid doing work in build
.
Use const
constructors; stable Key
s for stateful/collection items.
Separate presentation (widgets) from domain/logic (controllers/state/use cases).
Avoid passing BuildContext
deep for non-UI work; inject via providers.
Don’t store BuildContext
or MediaQuery
/Theme
in fields—read in build()
.
Prefer InheritedWidget
/providers over globals/singletons.
Single source of truth; unidirectional data flow; no hidden mutable state.
Explicit state types (e.g., Loading/Success/Error/Empty
); no nullable data as state.
Avoid calling setState
after dispose
; check mounted
or use notifiers/streams.
Avoid rebuilding whole trees—use selectors/listenable scopes.
Side effects isolated (e.g., effect hooks/controllers); no effects in build
.
State restoration considered for critical flows.
build()
is pure and fast: no I/O, no heavy computation, no async inside.
Use const
subtrees; memoize stable values; avoid creating new FocusNode/Controller
every build.
Use ListView.builder
/GridView.builder
with keys and itemExtent
/addAutomaticKeepAlives
as needed.
Use AnimatedBuilder
/ValueListenableBuilder
for fine-grained updates.
Use RepaintBoundary
/Clip*
carefully (clipping is expensive).
Avoid unnecessary setState
; batch updates.
Respect constraints; no unbounded height/width
in scrollables.
Efficient lists: prefer slivers for complex/long feeds.
Images sized with fit
and cache hints (cacheWidth/Height
when appropriate).
Avoid nested scrollables; use CustomScrollView
/slivers.
Text overflow/softWrap handled; no layout jumps.
Platform densities/touch targets respected.
Profiled in profile mode; no jank on mid-range devices.
Avoid synchronous heavy work on UI thread; offload to compute
/isolate.
Debounce/throttle rapid events (scroll, search).
Cache aggressively but safely (images, HTTP, domain caches).
Dispose Controller/FocusNode/AnimationController/StreamSubscription
.
Precache critical images; consider SkSL warm-up to reduce shader jank.
All await
ed Futures handled; no dangling Futures; explicit unawaited(...)
with comment if intentional.
Cancel timers/streams on dispose
; guard listeners.
Avoid async
in build
; use FutureBuilder/StreamBuilder
thoughtfully (no rebuild storms).
Use timeouts, retries with backoff, and cancellation.
Protect shared mutable state; no UI updates after disposal.
Long CPU tasks to isolates; I/O parallelism is bounded.
Router v2 used (or equivalent) with typed route data; no stringly-typed params.
Back/forward behavior correct on Android/iOS/Web; system back handled.
Deep links/URIs parsed robustly; missing params validated; guarded routes (auth/feature flags).
Route transitions/accessibility semantics preserved; route observers for analytics.
State restoration of navigation (where needed) implemented/tested.
Form
+ TextFormField
validators; async validation debounced.
Controllers/focus nodes disposed; input formatters for constraints.
Keyboard types and actions set; focus traversal defined.
Error messages accessible, concise, localized.
Pasting/IME/obscure text (password) handled securely.
Minimum touch target ≥ 48×48 dp; sufficient contrast; scalable text (respects textScaleFactor
).
Semantics labels/hints for non-text elements; images have semanticLabel
or are marked decorative.
Focus order logical; TalkBack/VoiceOver tested.
Motion/animation reduced with OS setting; don’t rely solely on color.
Adaptive layouts (phone/tablet/desktop/web); orientation changes safe.
Uses Flutter localization tooling; strings externalized (.arb or equivalent).
Pluralization/gender/bidi handled; date/number formats locale-aware.
No concatenated translatable strings; interpolation placeholders used.
Fallback locale defined; unsupported locales handled.
Right-to-left layouts validated.
Uses ThemeData
/ ColorScheme
tokens; no hard-coded colors/spacing/typography.
Dark/light/high-contrast variants consistent; dynamic color (M3) considered when relevant.
Component theming centralized; no per-widget one-off styling unless justified.
Iconography/assets match theme; elevation/shadows consistent.
Design tokens abstracted for reuse; spacing scale consistent.
API layer isolated; no HTTP calls in widgets.
Typed models with robust (de)serialization; unknown fields handled.
Timeouts, retries (exponential backoff + jitter), cancellation tokens in place.
Auth flows secure (token refresh, storage); 401/403 handled predictably.
Offline-first policy defined (cache, queue, reconcile on reconnect).
Network errors mapped to domain failures; no raw exceptions to UI.
Repository pattern; storage abstracted (SQLite/Isar/Hive/etc.).
Versioned, reversible migrations with tests; data loss risk assessed.
Indexing/perf considered; batch writes; WAL where supported.
Sensitive data encrypted at rest; keys from secure storage.
Cache invalidation strategy defined (TTL/etag/SWR).
Serialization evolves compatibly; nullability changes handled.
Domain-typed failures (no Exception
soup); user-safe messages.
Global error handling (Flutter FlutterError.onError
, zones) wired to crash reporting.
Structured logs (context, correlation IDs); log levels appropriate; PII scrubbed.
Metrics/traces for critical paths; app start time, frame build times monitored.
In-app non-fatal reporting and rate-limited to avoid loops.
Empty/error/timeout UI states are designed and tested.
No secrets in source; use env/CI secrets; platform keychain/keystore for tokens.
TLS required; cert pinning considered (with rotation plan).
WebViews locked down (JS, navigation whitelist); no arbitrary code exec.
Screenshots disabled for sensitive screens (platform flags).
Analytics/ads SDKs respect consent; minimal data collection; PII masked.
Obfuscation/minify set for release; code size and symbol upload configured.
Method/event channels typed; error codes mapped; codecs explicit.
Calls are idempotent/retry-safe; background thread correctness verified.
Permission prompts just-in-time with rationale; denied/permanent-denied paths handled.
Background modes (location/notifications) justified and throttled.
iOS/Android/Web parity considerations documented.
Minimal deps; actively maintained; license compatible.
Locked versions; reproducible builds; no git/path deps in release.
Null-safe packages; platform implementations vetted.
Remove transitive bloat when possible; tree-shakeable imports.
Vulnerability checks done; changelogs reviewed before bumps.
Fast unit tests for pure logic; widget tests for interactions; golden tests for visuals (with tolerances).
Integration/E2E cover critical journeys (auth, purchase, sync).
Deterministic tests (fixed clocks, seeded RNG, fake async).
Mocks/fakes not overused—prefer testable architecture.
Coverage targets met; flaky tests quarantined; CI gates on failures.
Semantics/a11y assertions where relevant.
dart analyze
clean; recommended/strict lints enabled (no ignores w/o rationale).
Format (dart format
) enforced; import sorting.
Code size/perf budgets enforced; PR blocks on regressions.
Duplicate code detection; dead code removed.
Secret scanning/license checks active.
Separate configs for dev/stage/prod (flavors); env handling secure.
Reproducible builds; cache key strategy; deterministic assets.
Android: min/target SDK sane; R8 shrink/opt; split per ABI; Play integrity.
iOS: bitcode (legacy), architectures, app thinning; provisioning/signing automated.
Versioning/semver consistent; changelogs; release notes automated.
Crash/ANR/metric dashboards part of release checklist; rollback path exists.
AppLifecycleState
handled (pause/resume/inactive/detached).
Background tasks constrained; alarms/workers rare and justified.
Network usage measured; large downloads chunked/resumable; metered networks respected.
Animations/frame timings within budget; no 60fps regressions.
Power-hungry features gated (GPS, BLE, camera) and batched.
Flags typed, discoverable, with owners; default safe/off.
Gradual rollouts (percent, cohorts); exposure logging.
Fallback paths tested; kill switches for risky features.
Config fetch cached and validated; stale config behavior defined.
Event schema versioned; no high-cardinality fields.
Screen names unified; navigation events deduped.
Consent flows meet GDPR/LGPD/CCPA; opt-out honored.
PII hashed or dropped; IP anonymization where applicable.
Sampling/rate limiting to control cost and noise.
PR description links issue/design; before/after screenshots for UI.
Checklists included (this file); risk/rollback documented.
Public APIs/behaviors documented; READMEs updated.
Migration notes included for breaking changes.
Ownership/tags set; reviewers appropriate; small, focused PR.
Let Kody automatically check quality, security and performance in every pull request—cloud or self-hosted, in under 2 minutes.