What does Riverpod's riverpod_lint package catch in @riverpod code, and how is it enabled in current Riverpod 3 projects?
answer
- analysis_server_plugin since 3.1.0
- plugins: key, not custom_lint
- dart analyze shows the warnings
- functional_ref, notifier_extends, notifier_build
- assist converts function to class
basics
~10 sriverpod_lint adds Riverpod-specific warnings, quick fixes and assists to the Dart analyzer. Since 3.1.0 it runs on analysis_server_plugin, enabled under plugins: in analysis_options.yaml, and checks the codegen contract plus general Riverpod mistakes.
solid answer
~30 sriverpod_lint 3.1.9 ships beside Riverpod 3.4.3. Since 3.1.0 it is built on `analysis_server_plugin` instead of `custom_lint`, so you list it under `plugins:` in `analysis_options.yaml` and both the IDE and `dart analyze` report its warnings; 3.1.9 requires Dart 3.13. Many rules guard the generator's contract: `functional_ref` (a `@riverpod` function without a `Ref` first), `notifier_extends` (a class not extending `_$Name`), `notifier_build`, `unsupported_provider_value`, `avoid_build_context_in_providers`, the `dependencies` rules for scoped providers, and the keepAlive-over-auto-dispose check. Others apply to any Riverpod code: `missing_provider_scope`, `provider_parameters`, `avoid_public_notifier_properties`. Assists convert a functional provider to a class and back, and wrap widgets in `Consumer` or `ProviderScope`.
code
yaml · 3 lines# analysis_options.yaml
plugins:
riverpod_lint: ^3.1.9go deeper
Know that riverpod_lint exists, that it warns about Riverpod mistakes such as a missing ProviderScope, and that dart analyze reports it.
Explain how 3.1 enables it through analysis_server_plugin and name the rules that guard the codegen contract, such as functional_ref, notifier_extends and notifier_build.
Show you rely on it in review and CI for lifetime and scoping errors, like keepAlive over auto-dispose and dependencies lists, and use its assists during refactors.
Decide which lint rules become team policy, how they gate CI, and how upgrading riverpod_lint tracks the Dart SDK version the team runs.
## What riverpod_lint is **riverpod_lint** is an optional developer package from the Riverpod repository — version 3.1.9 alongside Riverpod 3.4.3 — that adds Riverpod-specific warnings, quick fixes and refactoring assists to the Dart analyzer. It understands the contract riverpod_generator imposes, so many of its rules are marked as working only for providers written with `@riverpod`. ## How it runs today - Since **riverpod_lint 3.1.0** it is implemented with **analysis_server_plugin**, the analyzer's own plugin mechanism, instead of the older `custom_lint` package. - It is enabled by listing it under a top-level `plugins:` key in `analysis_options.yaml`, with `riverpod_lint:` and a version beneath it. - Once enabled, IDE diagnostics and `dart analyze` in a terminal or CI both report its warnings; no separate command is needed. - 3.1.9 requires Dart 3.13, because the analysis-server protocol it needs ships in that SDK; on older SDKs version solving now fails with a clear error instead of hanging `dart analyze`. The broader shape of `analysis_options.yaml` belongs to the analyzer topic. ## Rules that guard the codegen contract | Rule | Catches | |---|---| | `functional_ref` | a `@riverpod` function whose first positional parameter is not a `Ref` | | `notifier_extends` | a `@riverpod` class that does not extend `_$ClassName` | | `notifier_build` | a `@riverpod` class with no `build` method | | `unsupported_provider_value` | a generated provider returning a `StateNotifier`, `ChangeNotifier` or hand-made notifier without `Raw` | | `avoid_build_context_in_providers` | a `BuildContext` parameter on a provider or notifier method | | `only_use_keep_alive_inside_keep_alive` | a keepAlive provider reading an auto-dispose generated provider | | `provider_dependencies` | a `dependencies` list missing a scoped provider it uses, or listing one it should not | | `riverpod_syntax_error` | an error from the generator reported in the source file, e.g. an abstract notifier | The keepAlive rule's id in the 3.1.9 source is `only_use_keep_alive_inside_keep_alive`, although the README heading calls it `avoid_keep_alive_dependency_inside_auto_dispose`. ## Rules that apply to any Riverpod code - `missing_provider_scope`: `runApp` without a `ProviderScope` at the root. - `provider_parameters`: family arguments without a consistent `==`, such as a new list literal. - `avoid_public_notifier_properties`: public fields or getters on a Notifier, since state should flow through `state`. - `protected_notifier_properties`: one notifier touching another notifier's `state`, `future` or `ref`. - `avoid_ref_inside_state_dispose`: using `ref` inside a `ConsumerState`'s `dispose`. - `async_value_nullable_pattern`: matching `AsyncValue<int?>(:final value?)`, which skips a legitimate `null` value. ## Assists Refactorings include wrapping a widget in a `Consumer` or a `ProviderScope`, converting a widget to `ConsumerWidget` or `ConsumerStatefulWidget`, and **converting a functional `@riverpod` provider to the class variant and back** — handy when a derived value later needs a method that changes it. ## Reading a warning Each diagnostic carries the rule id, so a warning such as `notifier_extends` can be looked up in the package README, where every rule has a good and a bad example. Many rules come with a quick fix: adding the missing `extends _$ClassName` clause, adding a `build` method, adding the `Ref` parameter to a functional provider, or wrapping `runApp`'s argument in a `ProviderScope`. Because the rules run inside normal analysis, a team that already fails CI on analyzer warnings gets riverpod_lint enforcement for free once the plugin is enabled; a team that only treats errors as fatal will see these as warnings and must decide whether to make them blocking. ## Why teams adopt it 1. Mistakes in the generator's input otherwise surface only when the generator runs; the lint shows them in the editor as you type. 2. It encodes design rules — no public notifier fields, no `BuildContext` in providers — that code review would otherwise have to remember. 3. It catches lifetime and scoping mistakes, such as a keepAlive provider over an auto-dispose one or a missing `dependencies` list, that otherwise appear at runtime as memory that is never reclaimed or a `MissingScopeException`.
- Why does riverpod_lint discourage public fields on a Notifier?Widgets would read them through `ref.watch(provider.notifier).field`, which does not rebuild when the field changes, because only `state` changes notify listeners. The rule pushes all observable data into `state`; private members and ones marked `@protected` or `@visibleForTesting` are allowed.
- What do the dependencies rules protect against?A provider declared with `@Riverpod(dependencies: [...])` may be overridden in a nested ProviderScope. `provider_dependencies` checks that providers using scoped ones list them, and `scoped_providers_should_specify_dependencies` warns when a provider without dependencies is overridden below the root. Getting this wrong shows up at runtime as a MissingScopeException or an ignored override.
saying these in an interview costs you the question
- riverpod_lint still requires custom_lint and a dart run custom_lint step.
- riverpod_lint runs inside riverpod_generator during code generation.
- Every riverpod_lint rule works equally on hand-written providers.
- Lint warnings only appear in the IDE, never in dart analyze on CI.
- Notifiers may not declare fields of any kind, even private ones.