ProviderContainer
An isolated container that stores and manages providers outside the Flutter widget tree.
What is it?
ProviderContainer is the core object responsible for creating, storing, and managing providers.
While ProviderScope is used inside Flutter applications, it internally owns a ProviderContainer.
You typically interact with ProviderContainer when:
- Writing unit tests
- Running providers outside Flutter
- Creating isolated provider environments
- Overriding providers for testing
In most Flutter applications, you rarely create a ProviderContainer manually because ProviderScope does it for you.
Why does it exist?
Providers need somewhere to live.
Every provider instance, its state, dependencies, and lifecycle are managed by a container.
Without ProviderContainer, Riverpod would have nowhere to:
- Store provider state
- Resolve dependencies
- Cache providers
- Dispose unused providers
- Apply overrides
ProviderScope provides this automatically in Flutter, while ProviderContainer allows the same functionality outside the widget tree.
Syntax
Creating a Container
final container = ProviderContainer();
Explanation:
- Creates an isolated provider environment.
- No Flutter widgets are required.
Reading a Provider
final container = ProviderContainer();
final value = container.read(counterProvider);
Explanation:
read()returns the current provider value.- The provider is created automatically if needed.
Listening to a Provider
final container = ProviderContainer();
final subscription = container.listen(
counterProvider,
(previous, next) {
print(next);
},
);
Explanation:
- Observes provider changes.
- Unlike
read(), the listener continues receiving updates. - Remember to close the subscription when finished.
Disposing the Container
final container = ProviderContainer();
// Use providers...
container.dispose();
Explanation:
- Disposes every provider managed by the container.
- Always dispose containers you create manually.
Mental Model
Think of ProviderContainer as the engine that powers Riverpod.
Flutter App
│
▼
ProviderScope
│
▼
ProviderContainer
│
▼
Providers
Without Flutter:
ProviderContainer
│
▼
Providers
Every provider belongs to exactly one container.
Examples
Simple Example
final container = ProviderContainer();
final count = container.read(counterProvider);
print(count);
Explanation:
- Reads a provider without a widget.
- Useful for command-line apps or tests.
Unit Test Example
test('Counter starts at zero', () {
final container = ProviderContainer();
expect(
container.read(counterProvider),
0,
);
container.dispose();
});
Explanation:
- Creates a fresh provider environment for each test.
- Tests remain isolated from one another.
Using Overrides
final container = ProviderContainer(
overrides: [
apiProvider.overrideWithValue(
FakeApi(),
),
],
);
Explanation:
- Replaces dependencies only inside this container.
- Ideal for testing and mocking.
When to Use
Use ProviderContainer when:
- Writing unit tests
- Running providers outside Flutter
- Creating isolated provider environments
- Testing business logic
- Applying provider overrides
When NOT to Use
Avoid manually creating ProviderContainer when:
- Building a normal Flutter application
- You already have a
ProviderScope - Widgets can access providers through
WidgetRef
In Flutter, ProviderScope should usually manage the container for you.
Best Practices
- Create a new container for each test.
- Always dispose manually created containers.
- Use overrides to inject fake dependencies.
- Keep containers isolated between tests.
- Prefer
ProviderScopeinside Flutter applications.
Common Mistakes
Forgetting to Dispose
Wrong
final container = ProviderContainer();
Never disposing the container can leave providers alive longer than necessary.
Correct
final container = ProviderContainer();
try {
// Test code
} finally {
container.dispose();
}
Always dispose manually created containers.
Sharing One Container Across Tests
Wrong
final container = ProviderContainer();
test(...);
test(...);
State may leak between tests.
Correct
test('...', () {
final container = ProviderContainer();
// Test
container.dispose();
});
Each test should have its own container.
Creating a Container Inside Widgets
Wrong
final container = ProviderContainer();
Inside a Flutter widget.
Correct
Use WidgetRef or ProviderScope instead.
Related APIs
ProviderScopeWidgetRefProviderObserver.overrideWith.overrideWithValueConsumerWidget
Summary
ProviderContainer is the core object that manages providers, their state, and their lifecycle. It powers Riverpod behind the scenes and is most commonly used for testing, dependency injection, and running providers outside the Flutter widget tree. In Flutter applications, ProviderScope usually manages the container automatically.