no_magic_number
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.
Why use this rule
Section titled “Why use this rule”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,1and2are 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 * 1024counts as one named value. constdeclarations, enums and annotation arguments are exempt, for the same reason.- Measurements are exempt by default.
EdgeInsets,Gap,SizedBox,Durationand their siblings take numbers that are a measurement, not a policy. On a real Flutter app these accounted for 416 of 490 reports;spacing8is a worse name than8. - 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;Options
Section titled “Options”many_lints: rules: no_magic_number: allowed: [-1, 0, 1, 2] additional_ignored_invocations: [Insets] ignore_tests: truerules: 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/ |
Turning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: no_magic_number: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”no_magic_string— Name a string once it is repeated.prefer_moving_to_variable— Compute a repeated property or invocation chain once into a variable.avoid_accessing_other_classes_private_members— Make the underscore mean what everyone reads it as.avoid_commented_out_code— Detect and flag commented-out code.