Skip to content

no_magic_number

v1.0.0WarningConfigurableCode Quality

This rule flags a numeric literal used without a name to explain it.

This rule is in the pedantic preset: what counts as magic is a house style, and in a Flutter codebase full of layout numbers the honest default is off.

if (retries > 3) states a policy the reader cannot check and the next person cannot find: the same 3 appears in four other files, and changing the policy means finding all five. if (retries > maxRetries) says what the number is for and gives the change one place to happen.

The defaults are tuned so that only numbers carrying real meaning report:

  • -1, 0, 1 and 2 are always allowed. They are the vocabulary of indexing, counting and halving, and naming them makes code worse.
  • A literal that initialises a declaration is exempt — it is already named, and this is the shape the rule asks people to move towards. The check sees through arithmetic, so 100 * 1024 * 1024 counts as one named value.
  • const declarations, enums and annotation arguments are exempt, for the same reason.
  • Measurements are exempt by default. EdgeInsets, Gap, SizedBox, Duration and their siblings take numbers that are a measurement, not a policy. On a real Flutter app these accounted for 416 of 490 reports; spacing8 is a worse name than 8.
  • Tests are exempt by default. A fixture’s numbers are the test data, and naming each one buries the case it describes.

Two things this rule deliberately still reports: a const constructor argument (const EdgeInsets.all(17) still hides what 17 means, unless the type is in the ignore list), and seed or demo data. If a file is data, reach for exclude rather than weakening the rule.

bool tooManyRetries(int retries) => retries > 3;
const maxRetries = 3;
bool tooManyRetries(int retries) => retries > maxRetries;
// Always allowed: the vocabulary of indexing and counting.
int firstOrSentinel(List<int> xs) => xs.isEmpty ? -1 : xs.length ~/ 2;
// Already named — the check sees through the arithmetic.
const maximumStoredBytes = 100 * 1024 * 1024;
analysis_options.yaml
many_lints:
rules:
no_magic_number:
allowed: [-1, 0, 1, 2]
additional_ignored_invocations: [Insets]
ignore_tests: true
Option Type Default Description
allowed list of numbers [-1, 0, 1, 2] Numbers that never report
additional_allowed list of numbers [] Numbers to add to the defaults, instead of restating them
ignored_invocations list of strings [BorderRadius, Radius, EdgeInsets, EdgeInsetsDirectional, EdgeInsetsGeometry, Gap, SliverGap, SizedBox, Size, Offset, Duration, Rect, Alignment] Constructors and methods whose numeric arguments are a measurement
additional_ignored_invocations list of strings [] Names to add to that list
ignore_tests bool true Skip files under test/

To disable this rule:

many_lints.yaml
rules:
no_magic_number: false

To keep the rule on but skip certain paths, use per-rule exclude.