What is the difference between var, final, and const?

High PriorityAsked in ~80% of Flutter interviews

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?

KeywordReassignable?Value known atStored as
var✅ YesRuntimeNew instance each time
final❌ NoRuntime (first read)New instance each time
const❌ NoCompile timeCanonicalized (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

SituationPick
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

  1. Why does Flutter push so hard for const constructors? const widgets 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.

  2. Can a final variable hold a mutable object? Yes. final locks the reference, not the value. final list = [1, 2]; list.add(3); is perfectly valid.

  3. What's the difference between const on a variable vs a constructor? const on a variable means "this value is a compile-time constant." const on a constructor means "instances created with const MyWidget() are canonicalized." You need both for Flutter to reuse widgets.

How helpful was this content?

Please sign in to rate this article.