In a Dart or Flutter analysis_options.yaml, what do include:, linter: rules, analyzer: errors: and analyzer: exclude: each control?
answer
- one file at the package root
- includes merge in list order, local wins
- rules as a list or a map, not both
- errors: maps a code to a severity
- exclude: takes globs relative to the file
basics
~20 sinclude: pulls in shared option files such as a lint set; linter: rules switches individual lints on or off; analyzer: errors: changes a diagnostic's severity or ignores it; analyzer: exclude: removes files matching globs from analysis.
solid answer
~50 s`analysis_options.yaml` sits next to `pubspec.yaml`; if a package has none, the analyzer walks up the directory tree. `include:` takes one URI or a list: included files apply in order, each one's own includes first, and the local file overrides them all, merging rule by rule rather than replacing sections. `linter: rules:` is either a list of rules to enable or a map of `rule: true/false`, which is how you switch off a rule an included set enabled; you cannot mix the two forms in one `rules` entry. `analyzer: errors:` maps a diagnostic or lint name to `ignore`, `info`, `warning` or `error`. `analyzer: exclude:` lists globs, relative to the options file, such as `build/**` or `lib/**.g.dart`, whose diagnostics are not reported. `analyzer: language:` holds the strict modes, and a top-level `plugins:` key enables Dart 3.10's analyzer plugins.
code
yaml · 15 linesinclude:
- package:flutter_lints/flutter.yaml
- ../team_options.yaml
analyzer:
exclude:
- build/**
errors:
dead_code: info
missing_return: error
linter:
rules:
avoid_print: false
cancel_subscriptions: truego deeper
Recall the four keys and one example of each: include a lint set, enable or disable a rule, change a severity, exclude build output.
Explain the merge order across includes and the local file, why the map form is needed to disable an included rule, and how severity differs from enablement.
Show you keep one shared options file for a multi-package repo, use narrow suppression over broad excludes, and review rule changes like code.
Weigh a strict central rule set against per-package freedom in a multi-team codebase, including who owns upgrades and how exceptions are granted.
## Where the file lives and how it is found `analysis_options.yaml` configures the Dart **analyzer**, the engine behind IDE squiggles, `dart analyze` and `flutter analyze`. Put it at the **package root**, in the same directory as `pubspec.yaml`. If the analyzer finds no file there it **walks up** the directory tree and uses the first one it finds; with none at all it runs its default checks. In a repository with several packages, a package that has its own file uses that one, while packages without one inherit the nearest file above them. The file has a few top-level keys. This question covers the four most used ones: | Key | Controls | Typical value | |---|---|---| | `include:` | shared option files merged in first | `package:flutter_lints/flutter.yaml` | | `linter: rules:` | which lint rules are on or off | list of names, or `name: true/false` | | `analyzer: errors:` | severity of specific diagnostics | `todo: ignore`, `avoid_print: error` | | `analyzer: exclude:` | files not analyzed | `build/**`, `lib/**.g.dart` | Others exist: `analyzer: language:` for the strict type modes, top-level `plugins:` for analyzer plugins, and a `formatter:` section read by `dart format`. ## include: and merge order `include:` takes a single `package:` URI or relative path, or a **list** of them. The analyzer merges in this order: 1. the first included file, including anything it recursively includes; 2. each later included file, adding options or overriding conflicting ones; 3. finally the options written directly in this file, which override everything included. Merging is **per setting**, not per section. If an included set enables fifty rules and your file disables one, you get forty-nine; your `linter:` section does not wipe out the included one. Since Dart 3.10 the analyzer also reports when included files enable rules that are **incompatible** with each other, such as `prefer_single_quotes` and `prefer_double_quotes`. ## linter: rules in two shapes - **List form** enables rules: `- cancel_subscriptions`, `- close_sinks`. - **Map form** sets each rule explicitly: `avoid_print: false`, `unawaited_futures: true`. This is the only way to switch **off** a rule that an included set turned on. - YAML does not allow mixing the two in one `rules:` entry. An included file may use the other form. Lint rules report at **info** severity by default, which matters for CI gating. ## analyzer: errors: severities `errors:` is a map from a diagnostic code or lint name to one of four values: - `ignore`: never report it anywhere in the package; - `info`: report it without failing analysis; - `warning`: report it as a warning, which `dart analyze` treats as fatal by default; - `error`: report it as an error, which always fails `dart analyze`. It works for the analyzer's own diagnostics (`dead_code`, `invalid_assignment`, `todo`) and for lint names alike. It changes how a finding is **reported**, not whether the compiler accepts the code: `flutter run` does not read severities from this file. ## analyzer: exclude: globs `exclude:` lists file paths or glob patterns, **relative to the directory holding the options file**. Diagnostics are not reported for matching files. Typical entries are `build/**`, platform folders, and generated code such as `lib/**.g.dart` or `**.freezed.dart` when you do not want its findings. Excluding a file is coarse: every diagnostic for it disappears, including real errors, so it suits code you do not own or maintain by hand. ## A complete example ```yaml include: package:flutter_lints/flutter.yaml analyzer: exclude: - build/** - lib/**.g.dart errors: todo: ignore avoid_print: error linter: rules: avoid_print: true prefer_single_quotes: true use_key_in_widget_constructors: false ``` Reading it top to bottom: take flutter_lints' rules; skip build output and generated parts; hide `TODO` comments; make any `print` call an error; also enforce single quotes; and switch off one rule the included set enabled. ## Pitfalls - **Tabs or bad indentation** break YAML silently; use two spaces per level. - Using `exclude:` to silence one noisy rule hides every other finding in those files; `errors: <rule>: ignore` or `rule: false` is narrower. - Changes to `plugins:` need an analysis server restart before they take effect. - Enabling a rule and setting its severity are **separate**: `avoid_print: true` under `linter: rules:` makes the rule run, while `avoid_print: error` under `analyzer: errors:` decides how loudly it reports. Setting a severity for a rule that no included file or local entry enables has nothing to report. - A package nested inside another uses **its own** options file if it has one, not the parent's; a shared team file therefore has to be included explicitly (`include: ../../analysis_options.yaml`) when a nested package also needs local settings. ## Reading someone else's options file In an interview you may be handed an options file and asked what it does. Read it in merge order: resolve each `include:` first, then apply the local `linter:` toggles, then the `analyzer:` severities and excludes. Ask two questions of every entry: does it change **which** findings exist, or **how** they are reported?
- Two included files set the same rule differently and your file says nothing; which wins?The later file in the `include:` list. The analyzer applies included files in list order, each one's own includes first, and a later setting overrides an earlier one. Anything set directly in your `analysis_options.yaml` would override both.
- How do you enable an analyzer plugin in Dart 3.10 or later?Add a top-level `plugins:` map to `analysis_options.yaml`, keyed by the plugin package with a version constraint or a `path:`. Plugin warnings are on by default, while plugin lint rules stay off until you set them to `true` under that plugin's `diagnostics:` map. Restart the analysis server after changing the section.
- Why is exclude: a poor way to silence a single noisy lint?It removes whole files from reporting, so real errors and every other lint in them vanish too. To silence one rule everywhere, set it to `false` under `linter: rules:` or map it to `ignore` under `analyzer: errors:`; for one place, use an ignore comment.
saying these in an interview costs you the question
- Thinks a local linter: section replaces the included set's rules wholesale
- Writes rules as a list and then adds rule: false lines in the same entry
- Believes setting a lint to error makes flutter run refuse to build
- Uses exclude: with rule names instead of file globs
- Expects the first included file to override later ones