Riverpod DevTools Tracker
A powerful Flutter package that automatically tracks Riverpod state changes with detailed call stack information, helping you debug by showing exactly where state changes originated in your code.
ηΉι«δΈζ | English
Table of Contents
- Features
- Installation
- Quick Start
- How to Use DevTools Extension
- Configuration
- Console Output
- DevTools Extension Features
- Troubleshooting
- Requirements
Features
- π Automatic State Tracking - No manual tracking code needed
- π Code Location Detection - Shows exactly where state changes originated
- π Call Chain Visualization - View the complete call stack
- π¨ Beautiful DevTools Extension - GitHub-style dark theme UI
- β‘ Zero Configuration - Just add the observer and you're done
- π§ Highly Configurable - Customize what to track and how
Installation
Step 1: Add the Package
Add riverpod_devtools_tracker to your pubspec.yaml:
dependencies:
flutter_riverpod: ^3.1.0 # Required
riverpod_devtools_tracker: ^1.0.2
Step 2: Install Dependencies
Run the following command in your terminal:
flutter pub get
This package includes two components:
- Core Tracking:
RiverpodDevToolsObserverfor monitoring and recording state changes - DevTools Extension: Visual interface that's automatically discovered by Flutter DevTools
Note: The DevTools extension is automatically included in the package's
extension/devtools/directory. No additional installation or configuration needed.
Quick Start
Step 1: Import the Package
In your main.dart file, import the package:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_devtools_tracker/riverpod_devtools_tracker.dart';
Step 2: Add the Observer
Add RiverpodDevToolsObserver to your ProviderScope's observers list:
void main() {
runApp(
ProviderScope(
observers: [
RiverpodDevToolsObserver(
config: TrackerConfig.forPackage('your_app_name'), // Replace with your package name
),
],
child: const MyApp(),
),
);
}
Important: Replace
'your_app_name'with your actual package name frompubspec.yaml(thename:field value)
Step 3: Run Your App
flutter run
Done! Now when you run your app and open DevTools, you'll see the "Riverpod State Inspector" tab.
How to Use DevTools Extension
Step 1: Open DevTools
After running your app, you can open Flutter DevTools in several ways:
Method A - From VS Code
- Run your app (press F5 or click Run)
- Click the "Dart DevTools" button in the debug toolbar
- DevTools will automatically open in your browser
Method B - From Android Studio / IntelliJ
- Run your app
- Click "Open DevTools" in the Run panel
- DevTools will automatically open in your browser
Method C - From Command Line
- Run your app:
flutter run - The terminal will display a DevTools URL:
The Flutter DevTools debugger and profiler is available at: http://127.0.0.1:9100?uri=... - Click or copy the URL to open it in your browser
Step 2: Find the Riverpod State Inspector Tab
Once DevTools is open:
- Look for the "Riverpod State Inspector" tab in the top menu bar
- Click the tab to open the extension interface

Tip: If you don't see this tab, make sure:
- The package is properly installed and you've run
flutter pub getRiverpodDevToolsObserveris added to yourProviderScope- Your app has been restarted
Step 3: Understand the Interface Layout
The DevTools extension uses a two-panel layout:
Left Panel - Provider List (400px width)
- Displays all state changes in chronological order
- Each entry shows:
- Provider name and type
- Timestamp
- Change type (add/update/dispose/error)
- Code location where the change was triggered
- Click any entry to view details
Right Panel - State Details
- Shows detailed information about the selected state change:
- Before/after value comparison
- Complete call chain with file locations
- Function names in the call stack
- Clickable file paths for code navigation
![]()
Step 4: Track and Debug State Changes
As you interact with your app:
- Real-time Monitoring: Watch the left panel update in real-time as providers change
- Locate Issues: Click any change record to see the exact code location that triggered it
- Trace Execution: Use the call chain to understand the execution path
- Compare Values: Compare before/after values to debug state issues
Example Usage
Let's say you have a counter provider:
final counterProvider = StateProvider<int>((ref) => 0);
// In your widget
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: const Text('Increment'),
)
When you click the button:
- The DevTools extension immediately shows a new entry:
UPDATE: counterProvider - The location shows exactly where the button was pressed (e.g.,
widgets/counter_button.dart:42) - Click the entry to see the value changed from
0to1 - The call chain shows the complete path from button press to state update
Configuration
Basic Configuration
RiverpodDevToolsObserver(
config: TrackerConfig.forPackage(
'your_app_name',
enableConsoleOutput: true, // Print to console
prettyConsoleOutput: true, // Use formatted output
maxCallChainDepth: 10, // Max stack trace depth
maxValueLength: 200, // Max value string length
),
)
Advanced Configuration
RiverpodDevToolsObserver(
config: TrackerConfig(
enabled: true,
packagePrefixes: [
'package:your_app/',
'package:your_common_lib/',
],
enableConsoleOutput: true,
prettyConsoleOutput: true,
maxCallChainDepth: 10,
maxValueLength: 200,
ignoredPackagePrefixes: [
'package:flutter/',
'package:flutter_riverpod/',
'package:riverpod/',
'dart:',
],
ignoredFilePatterns: [
'generated.dart',
'.g.dart',
],
),
)
Console Output
When enableConsoleOutput is true, you'll see formatted output like this:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π UPDATE: counterProvider
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π Location: widgets/counter_button.dart:42 in _onPressed
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π Call chain:
β β widgets/counter_button.dart:42 in _onPressed
β providers/counter_provider.dart:15 in increment
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Before: 0
β After: 1
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
DevTools Extension Features
The extension provides a comprehensive debugging interface:
- Provider List - Real-time view of all state changes with timestamps
- Location Info - Shows the exact file and line number where each change originated
- Value Comparison - Before/after values displayed side by side for easy debugging
- Call Chain - Complete call stack for tracing the execution path
- Search & Filter - Quickly find specific providers or changes
- GitHub-style Dark Theme - Easy on the eyes during long debugging sessions
Provider State Filtering
You can quickly filter specific Provider state changes using the search box:

You can also focus on a specific Provider for in-depth analysis:

Tips for Using the Extension
- Finding State Bugs: Look at the call chain to understand why a state changed unexpectedly
- Performance Debugging: Check if providers are updating too frequently
- Code Navigation: Click on file paths in the call chain to jump to the code (if your IDE supports it)
- Filtering: Use the
packagePrefixesconfig to focus only on your app's code and filter out framework noise
Troubleshooting
DevTools Extension Not Showing
If you don't see the "Riverpod State Inspector" tab in DevTools:
- Make sure the observer is added: Check that
RiverpodDevToolsObserveris in yourProviderScope's observers list - Rebuild your app: Stop and restart your app after adding the package
- Check DevTools version: Make sure you're using a recent version of DevTools
- Verify the extension is built: The extension should be in
extension/devtools/directory
No State Changes Appearing
If the extension is visible but no state changes show up:
- Check packagePrefixes: Make sure your app's package name is included in the config:
TrackerConfig.forPackage('your_actual_package_name') - Verify providers are actually changing: Try a simple test like a counter to confirm tracking works
- Check console output: Enable
enableConsoleOutput: trueto see if changes are being tracked
Call Chain Shows No Location
If you see state changes but no file locations:
- Package name mismatch: Your
packagePrefixesmight not match your actual package structure - All locations filtered: Your
ignoredFilePatternsmight be too aggressive - Provider is auto-computed: Some providers update automatically based on dependencies - these won't have a specific trigger location
Performance Issues
If the tracker is slowing down your app:
- Disable console output: Set
enableConsoleOutput: falsefor better performance - Reduce call chain depth: Lower
maxCallChainDepthto 5 or less - Add more ignored patterns: Filter out high-frequency providers you don't need to track
- Disable in production: Only use the tracker in debug mode:
observers: [ if (kDebugMode) RiverpodDevToolsObserver(...) ]
Best Practices
For Production Use
We recommend disabling the tracker in production builds for optimal performance:
import 'package:flutter/foundation.dart';
void main() {
runApp(
ProviderScope(
observers: [
// Only enable tracking in debug mode
if (kDebugMode)
RiverpodDevToolsObserver(
config: TrackerConfig.forPackage('your_app'),
),
],
child: const MyApp(),
),
);
}
Performance Optimization
If you experience performance issues during development:
- Disable console output: Set
enableConsoleOutput: falsefor better performance - Reduce call chain depth: Lower
maxCallChainDepthto 5-8 for faster tracking - Filter aggressively: Add more patterns to
ignoredFilePatternsto reduce noise - Target specific providers: Use
packagePrefixesto focus only on your app's code
RiverpodDevToolsObserver(
config: TrackerConfig.forPackage(
'your_app',
enableConsoleOutput: false, // Better performance
maxCallChainDepth: 5, // Faster tracking
ignoredFilePatterns: ['.g.dart', '.freezed.dart'], // Less noise
),
)
Advanced Usage
Tracking Multiple Packages
If your app uses multiple custom packages:
RiverpodDevToolsObserver(
config: TrackerConfig.forPackage(
'my_app',
additionalPackages: [
'package:my_common/',
'package:my_features/',
],
),
)
Custom Filtering
Create highly customized filtering rules:
RiverpodDevToolsObserver(
config: TrackerConfig(
packagePrefixes: ['package:my_app/'],
ignoredFilePatterns: [
'.g.dart', // Generated files
'.freezed.dart', // Freezed files
'_test.dart', // Test files
'/generated/', // Generated directories
],
ignoredPackagePrefixes: [
'package:flutter/',
'package:flutter_riverpod/',
'package:riverpod/',
'dart:',
'package:go_router/', // Add other packages to ignore
],
),
)
Contributing
We welcome contributions! See CONTRIBUTING.md for guidelines.
Requirements
- Flutter SDK >= 3.27.0
- Dart SDK >= 3.7.0
- flutter_riverpod >= 3.1.0
License
MIT License - see LICENSE for details.
Support
- π Report Issues
- π¬ Discussions
- β If you find this package useful, please consider giving it a star on GitHub!