no_magic_string
This rule flags the same string literal repeated without a name.
Why use this rule
Section titled “Why use this rule”Unlike its numeric sibling, this rule reports only repetition — the case where a string is genuinely dangerous. A route path, a storage key or a header name written out at three call sites will eventually be changed at two of them, and the third failure is silent.
A single occurrence is left alone. It is usually a message or a label, and naming it moves the text away from the code that uses it for no gain.
This rule is in the pedantic preset: the threshold is a house style.
A storage key spelled out at each call site — rename it once and one of these is left behind:
class SessionCache { final Map<String, String> _box = {};
String? read() => _box['auth.refresh_token'];
void write(String token) => _box['auth.refresh_token'] = token;
void clear() => _box.remove('auth.refresh_token');}const refreshTokenKey = 'auth.refresh_token';
class SessionCache { final Map<String, String> _box = {};
String? read() => _box[refreshTokenKey];
void write(String token) => _box[refreshTokenKey] = token;
void clear() => _box.remove(refreshTokenKey);}The diagnostic appears at every occurrence rather than only the first: each one is separately editable, and showing one would hide the duplication the rule is about.
Exempting a wrapper that takes strings by design
Section titled “Exempting a wrapper that takes strings by design”A translation or logging helper is called with a literal key everywhere on purpose. Name it rather than turning the rule off:
many_lints: rules: no_magic_string: additional_ignored_invocations: [translate, featureFlag]rules: no_magic_string: additional_ignored_invocations: [translate, featureFlag]String translate(String key) => key;
// Not reported under the configuration above.final a = translate('cart.checkout');final b = translate('cart.checkout');final c = translate('cart.checkout');Raising the threshold
Section titled “Raising the threshold”Three occurrences is the default. Wait for a fourth with:
rules: no_magic_string: min_occurrences: 4Known limitations
Section titled “Known limitations”Two occurrences never report at the default min_occurrences: 3.
Strings shorter than min_length (3) are ignored — separators and punctuation rather than identifiers.
A literal that initialises a declaration is exempt, along with anything inside a const declaration, an enum, or an annotation. That is the shape the rule asks you to move towards.
Tests are exempt by default, where a repeated fixture string is the test data. Set ignore_tests: false to include them.
Options
Section titled “Options”many_lints: rules: no_magic_string: min_occurrences: 3 min_length: 3 additional_ignored_invocations: [translate] ignore_tests: truerules: no_magic_string: min_occurrences: 3 min_length: 3 additional_ignored_invocations: [translate] ignore_tests: true| Option | Type | Default | Description |
|---|---|---|---|
min_occurrences |
int | 3 |
How many times a string must repeat before it reports |
min_length |
int | 3 |
Shortest string considered; below this it is punctuation |
ignored_invocations |
list of strings | [] |
Constructors and methods whose string arguments never report |
additional_ignored_invocations |
list of strings | [] |
Names to add without replacing ignored_invocations |
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_string: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”no_magic_number— Give a number a name when it carries a policy.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.