The Art of Flutter Code Review: A Guide for Reviewers & Authors
SR
Sabin Ranabhat
December 31, 2025•6 min read

Code review is the primary mechanism for maintaining long-term system health, ensuring architectural integrity, and fostering team growth. It is not just about finding bugs; it is about ensuring the codebase remains predictable, maintainable, and scalable.
📖 What is Code Review? Code review is a quality assurance process where one or more developers examine code written by a teammate before it is merged into the main codebase. Think of it as a second set of eyes that helps catch bugs, improve code quality, share knowledge across the team, and ensure everyone follows the same standards.
📚 Related Guidelines: This guide works in tandem with:
- Submit Pull Request Like a Pro: For creating review-ready PRs.
- Conventional Commits: For standardizing git history.
✍️ The Author's Responsibility (Prerequisites)
High-quality reviews start with high-quality Pull Requests (PRs). Before requesting a review, the author must adhere to the Submit Pull Request standards:
- Atomic Scope: Keep PRs focused on a single purpose (aim for <400 lines). Small PRs result in better reviews and fewer bugs.
- Visual Proof: UI changes must include screenshots or screen recordings (as per the "UI Proof" guidelines).
- Self-Review: You are the first reviewer. Fix formatting, remove dead code, and ensure
flutter analyzepasses. - Context is King: The description must answer "What?" and "Why?", linking to relevant tickets.
🧠 Mindset & Human Factors
Effective code review requires psychological safety. We critique the code, not the coder.
| Guideline | Implementation |
|---|---|
| Assume Positive Intent | Frame feedback neutrally. |
| Distinguish preference vs. requirement | Use labels: [Blocking] for critical issues, [Nit] for optional polish. |
| Speed Matters | Aim for first feedback within 24 hours. Beyond 3 back-and-forths, hop on a call. |
Good vs. Bad Comment Examples
| ❌ Bad Comment | ✅ Good Comment | Why It's Better |
|---|---|---|
| "You forgot to handle nulls." | "Could we handle the null case here?" | Neutral, non-accusatory |
| "This is wrong." | "This might cause X issue because Y. What do you think?" | Explains reasoning, invites dialogue |
| "Don't do it this way." | "[Nit] Have you considered using X instead? It might be cleaner." | Labels as optional, offers alternative |
| "Fix this." | "[Blocking] This could cause a memory leak. We need to dispose the controller." | Explains severity and reason |
| "Why did you do this?" | "I'm curious about the reasoning here—could you elaborate?" | Genuinely curious, not attacking |
🛠️ The Technical Review Framework
Don't read line-by-line immediately. Use a multi-pass approach to catch high-level issues first.
Pass 1: Git Hygiene & Standards
Before looking at the code, check the metadata.
- Conventional Commits: Does the PR title and commit history follow the Conventional Commits specification?
- Format:
<type>(<scope>): <description>(e.g.,feat(auth): add login button). - Types:
feat,fix,refactor,style,chore,test,perf.
- Format:
- Clean History: Are "WIP" or "fix typo" commits squashed? The history should tell a clean story.
Pass 2: Architecture & Design (High Altitude)
- Does this solve the right problem?
- Is this the right place? (e.g., Logic in ViewModel vs View).
- Are boundaries respected? (No leakage of data models into UI layers).
- If the design is flawed, stop the review and discuss high-level changes.
Pass 3: Correctness & Logic (Deep Dive)
- Edge Cases: Nulls, empty lists, network errors, race conditions.
- State Management: Is state mutated safely?
- Tests: Do tests exist? Do they cover the behavior, not just lines?
- Complexity: Is the logic hard to follow? Can it be simplified?
Pass 4: Safety & Performance
- Security: Input validation, no hardcoded secrets, safe storage.
- Performance: No expensive loops, unnecessary rebuilds, or memory leaks (streams/controllers disposed).
Pass 5: Polish (Readability & Style)
- Naming: Descriptive names (
userIdvsid). - Docs: Comments added for complex logic?
🐦 Flutter & Dart Specifics
| Area | Checklist |
|---|---|
| Null Safety | • Avoid the force bang operator ! unless absolutely guaranteed.• Use late only when initialization is strictly guaranteed before use. |
| Async Safety | • Check Mounted: Always use if (!context.mounted) return; after an await before using BuildContext (e.g., popping or showing snackbars). |
| Widget Architecture | • No Logic in Build: The build() method must be pure and fast. No HTTP calls or complex filtering.• Extract Widgets: Break large build methods into smaller stateless widgets (adds const support). |
| Memory Leaks | • Dispose: Ensure TextEditingController, AnimationController, StreamSubscription are disposed.• Global Listeners: Careful with global ChangeNotifier listeners. |
| Performance | • Use const: Everywhere possible.• Build Scope: Use Selector or specific BlocBuilder filters to rebuild only what changed. |
⚖️ Resolving Disagreements
Disagreements are healthy, but stalemates are expensive.
- Discuss: Discuss in comments.
- Escalate: If unresolved after 3 replies, move to a synchronous call/huddle.
- Decide:
- If it's a matter of preference: The Author has the final tie-breaking vote (or follow the Style Guide).
- If it's a matter of correctness/risk: The Reviewer (or Tech Lead) has the veto.
- Commit: Once decided, move forward without resentment.
✅ Final Checklist
1. Prerequisites & Hygiene (Blocking)
-
Standards: Title follows Conventional Commits?
-
Scope: Is the PR size manageable (<400 LOC)?
-
Context: Is "Why" explained? Visuals attached for UI?
-
Architecture: Fits existing patterns?
2. Correctness & Logic (Blocking)
-
Functionality: Meets acceptance criteria?
-
Edge Cases: Nulls, errors, empty states handled?
-
Async Safety (Flutter):
context.mountedchecked afterawait? -
Memory: Controllers/Streams disposed?
3. Quality & Testing (Blocking)
-
Tests: Unit/Widget tests added?
-
Test Quality: Asserts behavior, not implementation?
-
Style/Lint: CI checks passed?
4. Polish (Non-Blocking / Nit)
-
Naming: Clear and descriptive?
-
Docs: Comments for complex logic?
References
- Google's Code Review Guidelines — Industry-standard best practices
- Conventional Commits — Commit message specification
- Effective Dart — Dart style and best practices
Share this article:
Related Posts

Blog
December 31, 2025
Mastering Flutter Pull Requests: Best Practices & Standards
Learn best practices for submitting high-quality Flutter pull requests, including writing clear titles, crafting strong descriptions, and adhering to community standards.

Blog
December 16, 2025
Conventional Commits: A Guide to Meaningful Git History
Instead of writing vague messages like 'fixed bug' or 'updates', this convention provides a rigorous rule set for creating an explicit commit history. This makes it easier to understand *what* happened in a project and *why*, and it enables potent automation tools (like automatic changelogs and version bumping).

Blog
February 22, 2024
Optimize Flutter Performance: Handle Heavy Image with Ease
Learn how to handle heavy images in Flutter using debugInvertOversizedImages and ResizeImage to optimize performance and memory usage.

Blog
February 4, 2024
Exploring Parallelism on Flutter: Main Thread, Isolate and Compute
Understanding the nuances of main thread, isolates, and compute empowers you to make informed decisions about concurrency in your Flutter projects.
© 2026 Sabin Ranabhat