Skip to content

prefer_declaring_const_constructor

v1.0.0WarningCode Quality

This rule flags a class that could declare a const constructor but does not.

A const constructor lets a value be built once at compile time and shared, rather than allocated at every call. In Flutter that is the difference between a widget the framework can skip rebuilding and one it cannot — which is why prefer_const_constructors is in every lint preset. But that rule only fires where a const constructor already exists; this one asks for the constructor in the first place.

This rule is in the pedantic preset.

A value class every call site has to allocate:

class ApiError {
final int status;
final String message;
ApiError(this.status, this.message);
}
class ApiError {
final int status;
final String message;
const ApiError(this.status, this.message);
}

Callers can now write const ApiError(404, 'Not found'), and the SDK’s prefer_const_constructors will start telling them to.

A class qualifies only when all of these hold, so most classes that look eligible are not:

Every instance field is final. One var and the class cannot be const. Static fields do not count.

There is exactly one generative constructor, and it is not already const. With none there is nothing to mark; with several, choosing which gets const is a judgement this rule will not make. Factory constructors are ignored.

Its body is empty and it does not redirect. A redirecting constructor’s constness is decided by its target.

Every initializer is const-evaluable. This is the one that catches people out — a field initializer whose value is a call cannot be const, and suggesting const for it produces code that does not build:

// Not reported: Random.secure() is a call, so `const` would not compile.
class TokenSource {
final Random _random;
TokenSource({Random? random}) : _random = random ?? Random.secure();
}

Literals, parameters, other constants, const Foo(), and arithmetic or conditionals over those all pass. A string interpolation, a bare Foo() or a cascade does not.

The superclass offers a const constructor to chain to. A const constructor can only call a const super constructor, so a class extending one without is skipped.

Abstract classes are skipped, and so are classes marked @immutable — the SDK’s prefer_const_constructors_in_immutables already owns those, and the two must never both report.

This rule is in the pedantic preset, so it is enabled by preset: pedantic or by name:

many_lints.yaml
rules:
prefer_declaring_const_constructor:
enabled: true

To disable this rule:

many_lints.yaml
rules:
prefer_declaring_const_constructor: false

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