Flutter · 15 min read

Flutter and Dart interview questions and answers

Flutter interview questions and answers on widgets, state, navigation and testing, plus Dart questions on async, the event loop and null safety.

This page is for Flutter engineers preparing a first or second round: a screen, a technical call, or the questions before a coding task. You get twenty-two Flutter interview questions and answers, each answer short enough to say out loud, and for most of them the trap or the follow-up the interviewer is likely to ask next. The Dart questions are here too, because in a Flutter loop they are asked in the same hour, not in a separate round. The worked example is the event loop, where a confident wrong answer is easy to give.

Widgets and the build method

1. “StatelessWidget or StatefulWidget?”

A StatelessWidget describes UI that depends only on its configuration and inherited data. A StatefulWidget has a State object that lives across rebuilds and can change. The follow-up: “Where does the state live?” In the State object, held by the element, not in the widget. The widget itself is immutable and rebuilt often.

2. “What does build do, and how often does it run?”

It returns a description of the UI for the current state. It can run many times: when setState is called, when an inherited dependency changes, when the parent rebuilds. The trap: side effects in build, such as starting a request. Every rebuild starts another one.

3. “What is a BuildContext?”

A handle to the widget’s location in the tree. It is how a widget finds inherited data such as the theme, MediaQuery or a provider above it. The follow-up: “Why does Navigator.of(context) sometimes fail right after an await?” The widget may have left the tree while waiting. Check mounted before using the context after an async gap.

4. “Walk me through the StatefulWidget lifecycle.”

createState, then initState once, didChangeDependencies when an inherited dependency changes, build as often as needed, didUpdateWidget when the parent rebuilds with a new widget of the same type, and dispose when it leaves the tree for good. The trap: forgetting dispose for controllers, focus nodes and stream subscriptions. That leak is easy to miss in review and shows up later as memory growth or callbacks on a dead screen.

5. “What are keys for?”

Keys tell Flutter which element belongs to which widget when widgets move. In a list of stateful items that can be reordered, a ValueKey built from the item’s id keeps each item’s state with the item. Without keys, state stays with the position. The deeper version of this question is on the senior Flutter guide.

State

6. “What are the limits of setState?”

It rebuilds only the widget that calls it and its descendants. That is right for local state. For state that distant widgets share, passing it down through constructors becomes prop drilling, and a shared owner becomes worth its cost. The follow-up: “Would you still use setState in an app that uses Riverpod or BLoC?” Yes, for state that belongs to one widget, like whether a panel is expanded.

7. “What is the difference between ephemeral state and app state?”

Ephemeral state lives in one widget and nobody else needs it: the current tab, the text in a field. App state is shared or must be kept between sessions: the signed-in user, the cart. The question is scored on whether you choose the tool from that difference rather than using one tool for everything.

8. “In Provider, what is the difference between watch, read and select?”

watch subscribes and rebuilds when the value notifies. read gets the value once without subscribing, for callbacks and commands. select subscribes to one derived value and rebuilds only when that value changes. The trap: read inside build as a way to stop rebuilds. The widget would show stale data, which is why Provider rejects it with an assertion in debug builds.

9. “How do you get a result back from a screen?”

final result = await Navigator.push(...) on the first screen, and Navigator.pop(context, value) on the second. The Future completes with the value, or with null if the user went back another way. The follow-up: “What if the first screen was disposed while waiting?” Check mounted before using the result to update state.

10. “Navigator 1.0 or the Router API?”

The imperative Navigator push and pop is fine for simple flows. Deep links, web URLs and a back stack that must be derived from app state are where the declarative Router API, usually through a routing package, pays for itself. The follow-up: “A deep link points to a profile that requires login.” The router checks auth state, sends the user to sign in, and continues to the original destination afterwards.

Async and the event loop (Dart)

11. “What is a Future, and what do async and await do?”

A Future is a value or an error that will be available later. An async function returns a Future. await pauses that function until the Future completes, without blocking the isolate, so other events keep being processed.

12. “Explain the Dart event loop.”

Each isolate runs one thread with an event loop and two queues. The microtask queue is for short internal follow-up work. The event queue is for I/O, timers, gestures and messages. After the current synchronous code finishes, the loop empties the whole microtask queue, then takes one item from the event queue, and repeats. The worked example below is the follow-up.

13. “How do you handle errors in async code?”

try and catch around the await, as with synchronous code, or catchError when not using await. The trap: a Future that nobody awaits. Its error is not caught where the candidate thinks it is, and it surfaces as an unhandled error elsewhere, or is lost.

14. “Single-subscription or broadcast stream?”

A single-subscription stream allows one listener and is used when the events are produced for that listener, like reading a file. A second listener throws. A broadcast stream allows many listeners, and a listener that joins late misses earlier events. The follow-up: “Who cancels the subscription?” The widget that listened, in dispose. Otherwise the listener outlives the screen.

15. “How do you cancel a Future?”

You cannot cancel a running Future itself. You can ignore its result, use CancelableOperation from the async package, model the work as a stream and cancel the subscription, or use a cancel token if the HTTP client provides one. Saying “you cannot” first, then the options, is the answer that scores.

Null safety and types (Dart)

16. “What does sound null safety give you, and what does late cost?”

Types are non-nullable unless marked with ?, and the compiler enforces it, so a whole class of null errors becomes compile errors. late defers initialisation to runtime. It is useful for fields set in initState, and it moves the check back to runtime: reading a late field before it is set throws.

17. “final or const?”

final is set once, at runtime. const is a compile-time constant and is implicitly final. In widgets, const constructors let Flutter reuse the same instance, so a const subtree is not rebuilt with its parent. The follow-up: “Does final List mean the list cannot change?” No. The reference is fixed, the contents are not.

18. “== or identical?”

identical checks whether two references are the same object. == calls the class’s equality, which is identity by default. A class that overrides == must override hashCode to match, or it breaks in sets and maps. State management libraries rely on this, which is why value equality matters in a Flutter app.

19. “What are records and patterns for?”

Records are small, immutable, typed groupings without a class, such as returning two values: (String, int) user() => ('Mina', 42); and final (name, score) = user();. Use a named class when the data has meaning, behaviour or a public API.

Isolates

20. “What is an isolate, and when do you use one?”

An isolate has its own memory and its own event loop. Isolates do not share memory and communicate by passing messages. Use one for CPU work long enough to miss frames, such as parsing a large JSON payload, with Isolate.run or compute. The trap: using one for small work. Starting an isolate and copying messages costs more than a short sort.

Testing

21. “What are the three kinds of Flutter tests?”

Unit tests for Dart logic, widget tests that build one widget with a WidgetTester and interact with it, and integration tests that run the app on a device or emulator. Most tests should be the first two kinds, because they are fast.

22. “pump or pumpAndSettle?”

pump renders one frame, optionally after advancing time. pumpAndSettle keeps pumping until no frames are scheduled, which is useful after a page transition. The trap: pumpAndSettle on a screen with an indefinite animation, such as a spinning progress indicator. Frames are always scheduled, so it times out. Use pump with a duration instead.

Worked example: the event loop

Question: “In what order do these lines print?”

import 'dart:async';

void main() {
  print('A');
  Future(() => print('D'));
  scheduleMicrotask(() => print('C'));
  print('B');
}

Answer: A, B, C, D. A and B are synchronous. C is a microtask, and the whole microtask queue runs before the next event. D is on the event queue.

The wrong answer: “Futures run in parallel, so it depends.” It sounds reasonable, and it is wrong. A Future does not create a thread. Everything here runs on one thread, in an order the rules determine.

The follow-up: “So why does a long for loop freeze the UI even inside an async function?” Because async does not move work off the isolate. A loop with no await in it runs to the end before the event loop can process a frame, a tap or anything else. That is starving the event loop, and the fix for real CPU work is an isolate, not another Future.

The second follow-up: “Can microtasks freeze the UI?” Yes. The loop drains the whole microtask queue before it takes the next event, so code that keeps scheduling microtasks, each one adding the next, never lets a frame or a tap through. The screen freezes as surely as with a long loop, and it is harder to find in a trace because every piece of work is short. It is also why a microtask is not a way to defer work until after the first frame: it runs before the next event, not after it.

Where to go for senior questions

This page covers the ground a Flutter interviewer expects any candidate to hold. At senior level the same topics come back with a harder second question: rendering and the three trees, state management scored on what it costs, isolates with plugins, and platform channels. Those are on Senior Flutter interview questions.

Sources

What to do next

Free guide: the Phoenix Method