Skip to content

Configuration

Add many_lints to the top-level plugins section in your analysis_options.yaml file (NOT under analyzer:):

plugins:
many_lints: ^1.1.0

The analysis server will automatically download and resolve the plugin from pub.dev. There is no need to add it to your pubspec.yaml.

Requires Dart 3.11+ (Flutter 3.41+)

You can use the extended syntax to pin a version:

plugins:
many_lints:
version: ^1.1.0

Every rule is off by default, but a preset is not required. You can enable only the rules you choose, start from a preset, or start from a preset and override individual rules. Installing the plugin alone therefore never floods an existing codebase with warnings.

Use this mode when you want a small, explicit rule set:

analysis_options.yaml
many_lints:
rules:
avoid_equal_expressions: true
avoid_only_rethrow:
enabled: true
exclude: test/**

The boolean and enabled: forms are equivalent. Adding include, exclude, message, or a rule-specific option also enables that rule unless you explicitly set enabled: false.

Presets are optional shortcuts for enabling a maintained group of rules. Select one with the preset: key, in either of the two config locations described below:

analysis_options.yaml
many_lints:
preset: recommended

The dedicated Presets guide explains the philosophy of every tier and lists the exact rules each one adds.

Preset Rules What it contains
none 0 Nothing. The default, and the explicit way to opt out.
core 35 Near-certain bugs only.
recommended 97 core plus likely defects and concrete runtime risks.
opinionated 184 recommended plus this package’s own style preferences.
pedantic 241 opinionated plus strict naming, structure, complexity and ordering.

Each preset builds on the one above it, the same way package:lints/recommended.yaml includes core.yaml — moving up a tier only ever adds rules.

core flags what is almost certainly a bug: a condition that is always true, a cast that can never succeed, an undisposed controller, an emit(state) that is silently dropped. Near-zero false positives and no stylistic judgement, so it is safe to adopt in a large legacy codebase.

recommended is the tier most projects want. It adds widely-agreed practice — using containsKey over keys.contains, passing an existing future to a FutureBuilder, keeping enum switches exhaustive. It deliberately excludes anything that imposes an architecture, a naming scheme, or a contested style choice.

opinionated adds the rules that enforce a particular taste (widget-swapping rules, shorthand preferences, prefer_type_over_var). Where reasonable codebases disagree, this tier takes a side — so expect to switch a few rules back off rather than to agree with all of it.

pedantic is the deliberately uncompromising tier. It adds one declaration per file, file/type-name matching, constructor-first member ordering, alphabetical ordering for named parameters, arguments, enum constants, map keys, record fields and pattern fields, complexity and size budgets, explicit callback parameter names, and stricter naming rules. It also removes the usual map[key]! exemption from avoid_non_null_assertion.

The plugin cannot enable SDK lints, so pair this preset with analyzer rules such as always_specify_types, directives_ordering, sort_constructors_first, sort_unnamed_constructors_first and sort_child_properties_last if you want the complete Flutter-strict style rather than only the custom rules supplied by this package.

Two other groups sit outside every preset. Rules that do nothing until you configure them — avoid_banned_imports, use_class_suffix and the rest of the banned_* family — because an unconfigured banned-list has nothing to report. And rules that assume a package you may not depend on, such as use_gap (the gap package) and the equatable rules.

enabled: overrides the preset for one rule, in either direction, so you never have to restate a preset’s contents to tweak it:

analysis_options.yaml
many_lints:
preset: recommended
rules:
# Add a rule the preset leaves out.
use_class_suffix:
enabled: true
entries:
- type: Bloc
suffix: Bloc
# Drop one the preset includes.
avoid_only_rethrow:
enabled: false

When a rule needs nothing but on-or-off, the terse spelling works too:

analysis_options.yaml
many_lints:
rules:
prefer_type_over_var: true
avoid_only_rethrow: false

preset: and enabled: decide whether a rule runs. To change how loudly it reports, use the analyzer’s own diagnostics: key:

plugins:
many_lints:
version: ^1.1.0
diagnostics:
avoid_equal_expressions: error # error | warning | info

A preset turns a rule on everywhere. To keep a rule on but silence it for certain paths, write a rules: block — in either of these two places, whichever you prefer.

The recommended location is a top-level many_lints: key in analysis_options.yaml — a sibling of plugins:, not nested inside it. A standalone many_lints.yaml next to pubspec.yaml is fully equivalent.

analysis_options.yaml
plugins:
many_lints: ^1.1.0
many_lints:
rules:
avoid_only_rethrow:
exclude:
- test/**
- "**/*.g.dart"

Use analysis_options.yaml for the normal single-file setup. Choose standalone many_lints.yaml only when you deliberately want plugin configuration separated. If you create both, many_lints.yaml wins outright; they are not merged.

Every rule supports exclude. Each exclude sits under one rule and affects only that rule — excluding a path from avoid_only_rethrow says nothing about the other rules. To skip a path for several rules, give each of them its own exclude.

Patterns are globs matched against the path relative to the package root, using the same glob semantics as the analyzer’s own analyzer: exclude:. A plain path is a valid pattern too, and the list can hold as many entries as you need:

analysis_options.yaml
many_lints:
rules:
avoid_only_rethrow:
exclude:
- lib/legacy/parser.dart # one specific file
- lib/generated/** # a whole directory tree
- "**/*.g.dart" # every generated file
prefer_type_over_var:
exclude:
- test/** # a different rule, its own list

include is the inverse of exclude: the rule runs only where it matches.

analysis_options.yaml
many_lints:
rules:
avoid_banned_imports:
include:
- lib/domain/** # architectural rules are most useful scoped

Like exclude, it takes globs relative to the package root, and a bare string works where you only need one pattern (include: lib/domain/**).

Omitting include, or leaving it empty, means “everywhere” — the default. When a file matches both lists exclude wins, so the two only ever narrow further and you never have to reason about which was written first.

message appends a sentence to every diagnostic a rule reports, which turns a generic lint into your team’s house style:

analysis_options.yaml
many_lints:
rules:
avoid_border_all:
message: Use AppBorders from our design system.
warning • Prefer Border.fromBorderSide over Border.all. Use AppBorders from our
design system. • many_lints/avoid_border_all

The rule’s own text is kept and the diagnostic code is unchanged, so // ignore: comments, severity overrides and quick fixes all keep working.

Both include and message work on every rule, exactly like exclude.

Beyond exclude, include and message, 120 rules accept options that change what they report. Those rules carry a Configurable badge on their page, and every option is documented there with its type and default.

Options go in the same rules: block as exclude, in whichever of the two files you chose above:

analysis_options.yaml
many_lints:
rules:
prefer_container:
exclude:
- test/** # works on every rule
min_sequence: 4 # an option, specific to this rule

Every option defaults to the rule’s previous behaviour, so adding this package’s options never changes results until you set one.

Rule Options
always_remove_listener state_base_classes
avoid_ad_hoc_left_type error_types, allow_subtypes
avoid_banned_annotations banned
avoid_banned_exports banned
avoid_banned_imports banned
avoid_banned_names banned
avoid_banned_types banned
avoid_empty_catch allow_with_comment
avoid_exit_outside_entrypoint allow_in, additional_allow_in
avoid_skipped_tests allow_reason
avoid_throw_in_fp_callback ignore_unimplemented, methods, additional_methods
avoid_collection_methods_with_unrelated_types strict
avoid_commented_out_code min_lines
avoid_default_tostring report_enums
avoid_duplicate_bloc_event_handlers additional_methods
avoid_duplicate_collection_elements ignore_literals
avoid_non_null_assertion ignore_checked_fields, ignore_map_indexes
avoid_empty_setstate state_base_classes
avoid_get_or_else_swallowing_failure ignore_tests
avoid_hooks_outside_build additional_methods
avoid_inherited_widget_in_initstate state_base_classes
avoid_late_context state_base_classes
avoid_missing_completer_stack_trace require_inside_catch
avoid_misused_hooks ignored_names, ignored_widgets
avoid_mounted_in_setstate state_base_classes
avoid_not_encodable_in_to_json allowed_types
avoid_only_rethrow ignore_typed_catches
avoid_passing_async_when_sync_expected ignore_widget_callbacks, ignored_parameters
avoid_recursive_widget_calls state_base_classes
avoid_removed_fpdart_api additional_removed
avoid_returning_widgets ignored_names, ignored_annotations, additional_ignored_annotations, allow_nullable
avoid_state_constructors state_base_classes
avoid_todo_comments markers, additional_markers, require_reference, reference_pattern
avoid_unassigned_stream_subscriptions ignored_instances
avoid_unnecessary_setstate state_base_classes
avoid_unnecessary_stateful_widgets state_base_classes
avoid_unnecessary_option ignore_public_api
avoid_unrelated_type_casts report_is_checks
avoid_unremovable_callbacks_in_listeners additional_methods
avoid_unrun_task additional_types, ignore_cascades
avoid_complex_conditions max_operands
avoid_long_functions max_lines
avoid_long_parameter_list max_positional, max_named
avoid_nested_conditional_expressions max_depth
banned_usage banned
check_for_equals_in_render_object_setters additional_methods
check_is_not_closed_after_async_gap additional_methods
dispose_fields cleanup_methods, additional_cleanup_methods, state_base_classes
dispose_provided_instances cleanup_methods, additional_cleanup_methods
emit_new_bloc_state_instances additional_methods
prefer_chaining_over_intermediate_run min_sequence
prefer_do_notation max_flat_map_depth, max_flatmap_depth (deprecated alias)
prefer_class_destructuring min_occurrences, ignored_types
prefer_container min_sequence
prefer_from_predicate max_condition_complexity
prefer_immutable_state name_pattern
member_ordering order
match_lib_folder_structure root
prefer_match_file_name ignored_suffixes, entrypoints, additional_entrypoints
prefer_correct_test_file_name directories, additional_directories
format_test_name pattern, check_groups
format_comment check_regular_comments
no_magic_number allowed, additional_allowed, ignored_invocations, additional_ignored_invocations, ignore_tests
no_magic_string min_occurrences, min_length, ignored_invocations, additional_ignored_invocations, ignore_tests
prefer_extracting_callbacks max_statements, report_functions, ignored_parameters, additional_ignored_parameters
prefer_named_parameters max_positional, ignored_names, additional_ignored_names, ignore_private_constructors
prefer_explicit_parameter_names min_parameters
prefer_explicit_type_arguments methods, additional_methods
avoid_accessing_other_classes_private_members ignored_members, additional_ignored_members
prefer_correct_type_name min_length, max_length, ignored_names
prefer_moving_to_variable max_extra_occurrences, allowed_duplicated_chains (deprecated alias), min_chain_length, ignored_invocations, ignored_targets
prefer_private_named_parameters only_same_name
prefer_safe_collection_access report_outside_pipelines, accessors, additional_accessors
prefer_shorthands_with_constructors classes, additional_classes
prefer_single_declaration_per_file kinds, types, ignore_private, ignore_visible_for_testing, groups
prefer_single_setstate state_base_classes
prefer_single_widget_per_file ignore_private_widgets, ignore_visible_for_testing
prefer_spacing min_children
prefer_string_parse_extensions additional_parsers
prefer_switch_expression allow_fallthrough_cases
prefer_task_either_over_try_catch class_suffixes, additional_class_suffixes, ignore_private
prefer_switch_with_enums ignore_contains
prefer_typed_exceptions allow, additional_allow
prefer_unit_over_void ignore_overrides
proper_super_calls state_base_classes
require_atomic_async_updates include_local_variables
require_mirror_test test_dir, suffix, fallback_anywhere
use_class_prefix entries, ignore_private
use_class_suffix entries, ignore_private
use_gap min_children
use_sliver_prefix state_base_classes
use_setstate_synchronously state_base_classes
match_class_name_pattern pattern
prefer_correct_error_name exception_suffix, error_suffix, allow_suffixes
prefer_correct_handler_name prefixes, additional_prefixes, require_private
prefer_correct_identifier_length min_length, max_length, allow_names, additional_allow_names
prefer_correct_setter_parameter_name parameter_name, allow_names
prefer_prefixed_global_constants prefix
arguments_ordering order, min_arguments
enum_constants_ordering order
initializers_ordering order
map_keys_ordering order, min_entries
parameters_ordering order, group_required, min_parameters
pattern_fields_ordering order
record_fields_ordering order
avoid_deep_nesting max_depth
avoid_high_cyclomatic_complexity max_complexity, count_exhaustive_switches
avoid_long_files max_lines, count_comments
avoid_too_many_methods max_methods, count_accessors
max_imports max_imports, count_exports
max_statements max_statements
avoid_negated_conditions report_not_equal
prefer_early_return min_statements
avoid_inconsistent_digit_separators group_size, hex_group_size
double_literal_format leading_zero, trailing_zero
avoid_future_of_either ignore_private
avoid_future_of_option ignore_private
prefer_typedefs_for_callbacks min_parameters
avoid_deep_widget_nesting max_depth
avoid_too_many_widgets_per_build max_widgets

state_base_classes is accepted by every rule that only applies inside a StatefulWidget’s State. Name a base class that does not extend Flutter’s State and those rules will treat it as one; an intermediate BaseState<T> that already extends State is recognised without any configuration.

Each option is documented with its type and default in the Options section of the rule’s own page.

Option names follow a fixed vocabulary, so the same idea always reads the same way:

Pattern Meaning
max_<unit> / min_<unit> A numeric bound; the unit is always named
ignore_<singular> A toggle that skips a whole class of thing (ignore_private)
ignored_<plural> A list of specific things to skip
<plural> Replaces a built-in list (cleanup_methods)
additional_<plural> Extends a built-in list (additional_cleanup_methods)
name_pattern A regular expression matched against a name
entries A list of maps, for rules driven entirely by what you configure

Prefer additional_* over restating a built-in list: a copied-out default silently misses any entry added in a later release.

A misspelled key is ignored, and a wrong-typed value falls back to the default rather than throwing. This is deliberate — a plugin cannot report problems against a YAML file, so a bad option cannot be surfaced as a diagnostic. If an option seems to have no effect, check its spelling and type against the rule’s page.

To suppress a specific lint, use comments:

// ignore: many_lints/prefer_center_over_align
const Align(alignment: Alignment.center);
// ignore_for_file: many_lints/use_class_suffix

VS Code: Open the command palette (Cmd+Shift+P / Ctrl+Shift+P) and run Dart: Restart Analysis Server.

Android Studio / IntelliJ: Go to File → Invalidate Caches / Restart, or use the Dart Analysis panel to restart.