ADR-001: State Management — Riverpod¶
Status: Accepted Date: 2026-02-07 Deciders: Dmitry Aleshkovskiy, Claude (AI assistant) Jira: AF-94
Context¶
App Factory is a new Flutter application that needs a state management solution. The app follows an offline-first architecture with background sync, requiring robust async state handling, caching, and testability.
Key requirements from the architecture: - Offline-first with local persistence (Drift/SQLite) - Background sync via Celery + polling - Multiple app variants from a single codebase - High testability (TDD mandatory) - Code generation acceptable (build_runner already planned)
Options Considered¶
1. BLoC (flutter_bloc)¶
- Pros: Battle-tested, strict Event/State pattern, good for large teams with strict conventions
- Cons: Significant boilerplate (Event + State + Bloc classes per feature), verbose for simple cases, steeper learning curve for async flows
2. Riverpod 2.x (flutter_riverpod + riverpod_annotation)¶
- Pros: Minimal boilerplate via
@riverpodcode generation, nativeAsyncNotifier+AsyncValuefor async/offline flows,ProviderContainerfor full test isolation, compile-time safety, noBuildContextdependency - Cons: Younger ecosystem, annotation-based API requires build_runner
3. Provider¶
- Pros: Simple, well-documented
- Cons: Being superseded by Riverpod (same author), limited async support,
BuildContextdependency
4. GetX¶
- Pros: Low boilerplate
- Cons: Poor separation of concerns, implicit magic, hard to test, not recommended for production apps
Decision¶
Riverpod 2.x with code generation (riverpod_annotation + riverpod_generator).
Rationale¶
- Less boilerplate: No Event/State class hierarchies — a
@riverpodannotation on a function or class is sufficient - Native async support:
AsyncNotifierandAsyncValuehandle loading/error/data states out of the box — critical for offline-first - Testability:
ProviderContainerallows full provider override in tests without mocking frameworks - Code generation: Already using
build_runnerfor Drift and JSON serialization — Riverpod fits the existing toolchain - Compile-time safety: Provider dependencies checked at compile time, no runtime errors
- No BuildContext: Providers accessible anywhere (services, repositories) without widget tree dependency
Packages¶
dependencies:
flutter_riverpod: ^2.6.1
riverpod_annotation: ^2.6.1
dev_dependencies:
riverpod_generator: ^2.6.3
build_runner: ^2.4.14
Consequences¶
- All state management uses Riverpod providers (no mixing with other solutions)
- Feature modules follow pattern:
provider.dart(state) +notifier.dart(logic) +widget.dart(UI) - Tests use
ProviderContainerwith overrides for dependency injection build_runnermust be run after changing@riverpodannotated code- Team members need to learn Riverpod patterns (AsyncNotifier, ref.watch, ref.read)
References¶
- Riverpod documentation
- Riverpod vs BLoC comparison
- App Factory architecture:
/docs/architecture.md