skip to content

Analyzer & Lints

The analysis_options.yaml file tunes the analyzer: include a lint set, switch rules on or off, raise severities and suppress findings with ignore comments. Interviewers ask how teams enforce style.

part ofDartoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In a Dart or Flutter analysis_options.yaml, what do include:, linter: rules, analyzer: errors: and analyzer: exclude: each control?

level: middleimportance: must knowfreq 58%

answer

  1. one file at the package root
  2. includes merge in list order, local wins
  3. rules as a list or a map, not both
  4. errors: maps a code to a severity
  5. exclude: takes globs relative to the file

basics

~20 s

include: 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 lines
yaml
include:
  - 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: true

go deeper

for a junior

Recall the four keys and one example of each: include a lint set, enable or disable a rule, change a severity, exclude build output.

for a middle

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.

for a senior

Show you keep one shared options file for a multi-package repo, use narrow suppression over broad excludes, and review rule changes like code.

for a principal

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
open as a page

In Dart and Flutter, what are the lints package's core and recommended sets and flutter_lints, and which does a new Flutter app include?

level: juniorimportance: should knowfreq 45%

basics

~10 s

The lints package ships two Dart-team rule sets: core catches critical problems, and recommended includes core plus idiomatic-style rules. flutter_lints builds on recommended with Flutter rules, and flutter create includes package:flutter_lints/flutter.yaml.

open as a page

How do you make dart analyze fail a CI job on lint findings, and what do its --fatal-infos and --fatal-warnings flags change?

level: middleimportance: should knowfreq 34%

basics

~20 s

Lints report at info severity, and dart analyze exits 0 on infos unless you pass --fatal-infos (exit 1). Warnings are fatal by default (exit 2), errors always exit 3; alternatively raise chosen rules to warning or error under analyzer: errors:.

open as a page

In Dart, when do you silence an analyzer finding with an ignore comment, ignore_for_file, analyzer errors: ignore, or analyzer exclude:?

level: middleimportance: should knowfreq 40%

basics

~10 s

Use // ignore: for one line, // ignore_for_file: for one file (type=lint covers every lint), analyzer errors: <code>: ignore to drop one diagnostic package-wide, and analyzer exclude: to stop reporting whole files by glob.

open as a page

A legacy Dart codebase leans on dynamic values and raw generic types; how do you roll out strict-inference, strict-casts and the no_raw_types lint without stalling the team?

level: seniorimportance: should knowfreq 24%

basics

~20 s

Measure first, then tighten in stages: enable one check at a time, fix module by module starting at dynamic boundaries such as jsonDecode, keep new code clean, and make it blocking once findings reach zero. On Dart 3.13 prefer the no_dynamic_casts and no_raw_types lints.

open as a page