skip to content

A five-person team is starting a Flutter clinic-appointment app; how would you choose its state management library and make the choice hold as the app grows?

level: principalimportance: should knowfreq 45%

answer

  1. list the app's state first
  2. weight the criteria for this team
  3. spike one real feature twice
  4. write the decision down
  5. conventions plus lint and review

basics

~20 s

Inventory the app's state, weight scope, testability, boilerplate, async needs and team skills, then spike one real flow, such as booking a slot, in the two leading candidates. Record the decision with its reasons, and enforce conventions so five people use it one way.

solid answer

~50 s

I would start from the app, not the libraries: a clinic-appointment app has mostly server-backed async state (slots, bookings, reminders), a signed-in user shared app-wide, and form state that is ephemeral. Weighted for five people: async handling and testability high, boilerplate medium, existing team skill high. That usually narrows to Riverpod (strong async model, per-test overrides) or BLoC (explicit events and states, `blocTest`), with plain `ChangeNotifier` view models as the baseline to beat. I would build the booking flow in both, compare code size, tests and how errors and retries look, and pick one. Then I would write a short decision record with the trade-offs, fix conventions (folder per feature, one pattern for async states, no side effects inside build methods), add a sample feature and review checklists, and name the trigger for revisiting it.

go deeper

for a junior

Recall that ephemeral state can stay in setState and that a library is chosen for shared, long-lived state.

for a middle

Explain how the criteria of scope, testability, boilerplate and async needs map to the app's actual state.

for a senior

Run a time-boxed spike of a real flow in two candidates and compare code, error handling and tests as evidence.

for a principal

Own the decision record, the conventions and the revisit trigger, and keep the library at the edges so the choice remains reversible.

## Start with the state, not the library A state-library choice is only defensible against the app it serves. For a **clinic-appointment app**, an inventory might look like this: | State | Scope | Nature | |---|---|---| | Available slots, bookings, doctors | several screens | async, server-backed, needs refresh and retry | | Signed-in patient and session | app-wide | long-lived, changes rarely | | Booking form fields, selected date | one screen | ephemeral, `setState` is fine | | Reminders and notification settings | a few screens | persisted locally | The inventory already says something: most shared state is **async data from a backend**, and the ephemeral part needs no library at all. ## Weight the criteria for this team For five developers who will work on the app for years: - **Async handling**: high weight; most screens load, fail and retry. - **Testability**: high; booking logic is business-critical and should be tested without widgets. - **Boilerplate**: medium; five people can absorb some ceremony if it buys consistency. - **State scope**: shared across several screens, but not one global blob. - **Team skill and hiring**: what the five already know, and what new hires are likely to know. ## Shortlist and spike 1. Keep the **documented baseline** as a control: `ChangeNotifier` view models with `ListenableBuilder`, dependencies injected with `provider`. 2. Shortlist the libraries that score well on the heavy criteria. For this profile that is typically **Riverpod** (`AsyncValue` for loading and error, per-test overrides, automatic retry in Riverpod 3) and **BLoC** (explicit events and states, `blocTest`). 3. **Spike one real flow**, such as "pick a doctor, see slots, book, handle a conflict", in each candidate. Time-box it to a few days. 4. Compare concrete evidence: lines of code, how the slot-conflict error is represented, how the test reads, how a new developer understands the flow. The spike is what turns a preference into an argument. ## Decide and record it Write a short **decision record**: - the criteria and their weights; - the candidates and the spike results; - the choice and the costs accepted (for example BLoC's event classes, or Riverpod's learning curve); - the **trigger to revisit**: a major version that reshapes the API, a new platform target, the team doubling. ## Make it hold A library chosen and then used five different ways is worse than any single choice. To keep it consistent: - **Conventions**: one folder layout per feature, one pattern for async states, one way to inject repositories. - **A reference feature** that new code copies. - **Tooling**: lint rules the library ships or the team configures, plus a review checklist item. - **Boundaries**: keep repositories and services free of the library, so a later migration touches only the UI and view-model layer. - **Pin versions** and plan major upgrades deliberately; Riverpod 3 moving older provider types to `legacy.dart` is the kind of change to budget for. ## What makes the answer principal-level There is no single right library. What the interviewer evaluates is whether you: - derive the choice from the app's state and the team's constraints; - produce evidence (a spike) rather than an opinion; - account for cost over time: onboarding, consistency, upgrades and exit; - leave a written record so the decision can be revisited on purpose rather than eroded by drift.

  • In a Flutter app, how do you keep a later state-library migration from becoming a rewrite?
    Keep the library at the edges: repositories and services are plain Dart with no library types, and view models or blocs depend on them through constructors. Then a migration replaces only the view-model layer and widget bindings, feature by feature, while data access and business rules stay untouched.
  • In a Flutter team, what would make you revisit the state library decision?
    A trigger written into the decision record: a major version that changes the core API, repeated bugs traceable to the pattern, a new target such as web with URL-driven state, or the team growing enough that the current conventions no longer hold. Without such a trigger, churn costs more than it saves.
  • In a Flutter team, why spike the same flow in two libraries instead of reading comparisons?
    Comparisons describe other apps. A spike on your own hardest flow shows the real code size, how your errors and retries look, and whether your developers can read the result, which is the evidence a team decision needs.

saying these in an interview costs you the question

  • Pick the most popular library and move on
  • Every piece of state, including form fields, belongs in the library
  • The decision needs no written record for a five-person team
  • Mixing several state libraries freely gives each developer flexibility
  • Repositories should depend directly on the chosen library's types