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.

  4. When would you use late final instead of final? When you can't initialize at declaration but still want single-assignment semantics — common for dependency injection and initState setup.

How helpful was this content?

Please sign in to rate this article.