What is the difference between var, final, and const?
3 min read
Dart Fundamentals
Dart gives you three ways to declare a variable, and they answer two different questions: can it change? and when is the value known?
| Keyword | Reassignable? | Value known at | Stored as |
|---|---|---|---|
var | ✅ Yes | Runtime | New instance each time |
final | ❌ No | Runtime (first read) | New instance each time |
const | ❌ No | Compile time | Canonicalized (shared) |
The killer feature of const is canonicalization: two const values that look the same are the same object in memory. That's why Flutter widgets love it.
Code in action
// var → mutable
var city = 'Bengaluru';
city = 'Mumbai'; // ✅ ok
// final → set once, computed at runtime
final loggedInAt = DateTime.now(); // ✅ runtime value is fine
// loggedInAt = DateTime.now(); // ❌ cannot reassign
// const → must be known at compile time
const pi = 3.14159; // ✅
// const now = DateTime.now(); // ❌ not a compile-time value
// final allows mutable *contents*, const does not
final cart = [1, 2, 3];
cart.add(4); // ✅ list is final, not its items
const menu = [1, 2, 3];
// menu.add(4); // ❌ const collections are deeply immutable
// const is canonicalized — same object in memory
const a = [1, 2, 3];
const b = [1, 2, 3];
print(identical(a, b)); // true 🎉
When to use which
| Situation | Pick |
|---|---|
| Value will change (counters, inputs, state) | var |
Value is set once but depends on runtime (API response, DateTime.now()) | final |
Value is a hard-coded literal (EdgeInsets.all(16), colors, strings) | const |
Rule of thumb: try const first, fall back to final, use var only when you must mutate.
Common mistakes to avoid
// ❌ Reaching for var by habit
var userId = response.userId; // never reassigned
// ✅ Signal immutability
final userId = response.userId;
// ❌ Missing free performance wins in widgets
return Padding(
padding: EdgeInsets.all(16), // rebuilt on every build()
child: Text('Hi'),
);
// ✅ const lets Flutter skip the rebuild entirely
return const Padding(
padding: EdgeInsets.all(16),
child: Text('Hi'),
);
// ❌ Thinking final makes the object immutable
final users = <String>[];
users.add('Alice'); // works! final only locks the reference
// ❌ Using ! on a final to "fix" a null error — usually a sign you wanted `late`
Interview follow-ups
-
Why does Flutter push so hard for
constconstructors?constwidgets are canonicalized — Flutter reuses the same instance across builds and can skip the subtree's rebuild entirely. In large trees, this is a real, measurable win. -
Can a
finalvariable hold a mutable object? Yes.finallocks the reference, not the value.final list = [1, 2]; list.add(3);is perfectly valid. -
What's the difference between
conston a variable vs a constructor?conston a variable means "this value is a compile-time constant."conston a constructor means "instances created withconst MyWidget()are canonicalized." You need both for Flutter to reuse widgets. -
When would you use
late finalinstead offinal? When you can't initialize at declaration but still want single-assignment semantics — common for dependency injection andinitStatesetup.
How helpful was this content?
Please sign in to rate this article.