Almost nobody learns Dart first. Interviewers know that, and the questions are calibrated around it — they're looking for the places where someone writes Java or JavaScript in Dart syntax and never notices.
These twenty are language questions only. The concurrency model, isolates and null safety come up in Flutter loops and are covered there: Flutter interview questions. Everything below is Dart the language, which is increasingly asked on its own.
Immutability and identity
The opening group almost everywhere. Cheap to ask, and the answers separate quickly.
- What's the difference between
finalandconst? - What does
lateactually do, and when is it a mistake? - What are records, and when would you use one instead of a class?
- If you override
==, what else must you do, and why?
Saying it out loud: question 1 gets answered as "both mean you can't change it", which is the wrong half. "final is about assignment — one time, at runtime. const is about the value existing at compile time, and it's canonicalised: two identical const values are the same object. So final list = [1,2] gives me a list I can still add to, and const list = [1,2] gives me one that's deeply immutable and shared. The identity part is the bit people miss — identical(const A(1), const A(1)) is true, and that's load-bearing in frameworks that compare objects to decide whether to do work."
Question 2 has a real answer about cost, not just mechanics: "late defers initialisation and moves a compile-time guarantee to a runtime one. It's right when initialisation genuinely can't happen at construction — something needing this, or an expensive value you want computed once on first read. It's a mistake when it's used to silence the compiler about a field that should have been nullable, because then you've swapped a type you'd have to handle for a crash you won't see until production."
Question 4's answer is short and the follow-up is where it lands: hashCode must agree with ==, otherwise objects vanish inside sets and maps. Worth adding that records give you both for free, which is half the reason to use them.
Composing behaviour
Where Java and TypeScript habits show up most.
- Mixin, abstract class, interface — when do you reach for each in Dart?
- What does the
onclause in a mixin declaration do? - How do extension methods dispatch, and what can't they do?
- What do sealed classes give you that an abstract class doesn't?
Saying it out loud: question 7 is the one that catches people, because extensions look like methods and don't behave like them. "Extension methods are resolved statically, at compile time, from the static type of the expression. So they can't be overridden, they're invisible to dynamic, and if two extensions in scope define the same member you get an ambiguity error rather than an override. Which means they're excellent for adding convenience to a type you don't own, and wrong for anything that needs polymorphism."
Question 8's answer is exhaustiveness: "Sealed means every direct subtype is in the same library, so the compiler knows the full set — and a switch over them is checked for completeness. Add a new subtype and every switch that doesn't handle it stops compiling. That's the whole value: it turns 'did I handle every case' from a code review question into a compiler error."
The thread through this group is that Dart has more ways to compose than most languages people arrive from, and each one is narrower than it looks. A mixin is not a trait with state you can do anything with; an extension is not a method; a sealed class is not just an abstract class with a naming convention. Candidates who describe all four as "ways of sharing code" are describing the category rather than the choice, and the choice is what's being asked about.
Generics, and Dart's deliberate hole
One question here separates people who have read the spec from people who haven't.
- Is
List<int>a subtype ofList<num>in Dart? What are the consequences? - What does the
covariantkeyword do on a parameter? - When would you write a bounded type parameter —
T extends Comparable<T>? - What's the difference between
dynamicandObject??
Saying it out loud: question 9 is the interesting one and the honest answer names a deliberate unsoundness. "Yes — Dart's generics are covariant, so a List<int> is a List<num>. That's convenient and it isn't sound: you can assign a List<int> to a List<num> variable and then try to add a double to it. Dart accepts that at compile time and throws at runtime, because the list carries its real type. It's a deliberate trade — the alternative is declaration-site variance that most people find painful — but it means a type error you'd expect the compiler to catch shows up as a TypeError in production."
Question 12's answer in one line: "Object? accepts anything and lets you call almost nothing until you check. dynamic accepts anything and lets you call everything, with all the checking deferred to runtime. Object? is what you usually want; dynamic is what you use when you're parsing JSON and haven't validated it yet."
Collections, and the laziness that surprises people
- Is
mapon anIterableeager or lazy? How do you know? - What happens if you modify a collection while iterating it?
- When does
where().map().firstdo less work than you'd expect? - Spread, collection-if, collection-for — what are they for beyond syntax?
Saying it out loud: questions 13 and 15 are really one question, and the answer is worth having ready: "map and where on an Iterable return lazy views — nothing runs until something consumes them. So list.where(expensive).map(transform).first evaluates expensive until the first match and then stops, which is usually what you want and occasionally a trap: if the transform has a side effect, it only happens for the elements actually consumed. toList() forces it. And because the view holds a reference to the source, a lazy chain over a collection that then changes gives you a concurrent-modification error at a confusing place."
Question 14 has a precise answer — ConcurrentModificationError — and the useful addition is what to do instead: iterate a copy, or collect the removals and apply them after.
Errors and construction
ExceptionorError— which do you throw, and which do you catch?- What can a factory constructor do that a generative one can't?
- What's the point of a named constructor over a static method?
- What does the cascade operator buy you, and when does it hurt readability?
Saying it out loud: question 17 has a convention behind it that many candidates have never been told. "Error is for programming mistakes — a failed assertion, an argument that should never have been that value, a state that shouldn't exist. Those are bugs and catching them usually hides the bug. Exception is for conditions a correct program still has to handle: the network failed, the file wasn't there, the input didn't parse. So I throw Exception subtypes for anything a caller might reasonably recover from, and I let Error crash."
Question 18: "A factory doesn't have to create a new instance. It can return a cached one, a subtype, or an instance from a pool — which is why int.parse and most fromJson constructors are factories. A generative constructor always produces a fresh object of exactly that class."
Describing the category
“Mixins, interfaces and abstract classes are all ways to share behaviour between classes — you pick based on the situation.”
True in any object-oriented language and specific to none. It tells the interviewer you've read the list and never had to choose between them under pressure, which is exactly what they were checking.
Naming the constraint
“Extensions dispatch statically from the static type — so they can't be overridden and they're invisible to dynamic. That's why they're for convenience on types you don't own.”
One mechanism, one consequence, one usage rule that follows from it. This is what the whole page is looking for: the answer continues past the definition into what it means for code you'd write.
Preparing
The fastest way to find your own gaps is to open the last Dart file you wrote and ask three questions of it: where did I use final where const would work, where did I use late to avoid thinking about null, and where did I write a helper that should have been an extension?
Most people find at least two, and each one is a ready-made answer — a specific thing in your own code, which is always more convincing than a definition.
If the loop is a Flutter one rather than a language one, the framework half — widgets, rebuilds, the concurrency model — is here: Flutter interview questions. And if you're being asked to justify the framework choice itself, that's a different conversation: React Native vs Flutter.
Practical target: answer question 1 out loud and keep going past the definition. Almost everyone stops at "final is runtime, const is compile time" — the sentence that scores is the next one, about canonicalisation and why two identical const values are the same object. Every question on this page has a second sentence like that, and the second sentence is the answer.




