Dart's Microtask Queue vs. Event Queue

Dart's event loop prioritizes a 'microtask' queue for immediate async tasks over the main 'event' queue for I/O and user input. This ensures high-priority code runs first, but risks starving the event queue and freezing the UI if overused.
Why it exists
Dart is single-threaded, so it needs a way to handle asynchronous operations without blocking the main thread. While a single event queue handles things like user input and I/O, some async tasks need to run immediately after the current task finishes, before any other external events. This requires a two-tiered priority system.
The mental model
Think of the event loop as a manager with two inboxes. The 'microtask' inbox is for urgent, internal memos that must be handled right now. The 'event' inbox is for regular mail like user input, network responses, or timers. The manager will always clear the entire urgent inbox before even looking at a single piece of regular mail.
How it works
Every Dart isolate has a single thread running an event loop. This loop services two queues: the microtask queue and the event queue. On each tick, the loop first checks the microtask queue. If it contains any tasks, the loop executes them one by one until the queue is empty. Only when the microtask queue is completely empty will the loop take and process just one item from the event queue. This cycle repeats. You can add to the microtask queue with Future.microtask(). Most other async operations, like a regular Future() or I/O, add tasks to the event queue.
When to use it
Use the microtask queue for very short, immediate asynchronous actions that need to complete before the UI can update or another event is processed. For example, you might use it to clean up a resource or run a callback right after a synchronous code block finishes, but before Dart handles the next user tap or timer. It's for internal, programmatic ordering.
When not to use it
Avoid the microtask queue for anything long-running or for tasks that can wait. Never perform I/O or any computation that could take more than a few milliseconds in a microtask. The biggest footgun is creating a microtask loop, where one microtask schedules another. This will permanently block the event queue, starving it of processing time. This freezes the app, as UI rendering and user input are handled by the event queue. When in doubt, use a regular Future which uses the event queue.
One canonical example
Imagine you have code that needs to run asynchronously but before the next frame renders. Using Future.microtask(() => print('Running microtask')) ensures that 'Running microtask' is printed before Dart processes any pending user clicks or timer events. In contrast, Future(() => print('Running event')) would place the task on the event queue, meaning it might run after several other events if they were already waiting.
Interview question
What is the most significant consequence of placing a long-running or continuously scheduling task in Dart's microtask queue?
- a.It will delay the execution of other microtasks, creating a backlog in the microtask queue.
- b.It will cause the Dart VM to allocate excessive memory, leading to an OutOfMemoryError.
- c.It will prevent the event queue from processing tasks, resulting in UI unresponsiveness and app freezes.Correct
- d.It will lead to increased CPU usage but will not directly impact the responsiveness of the application.
Why? this is the answer
The card explicitly states that a long-running or looping microtask "will permanently block the event queue, starving it of processing time," which "freezes the app, as UI rendering and user input are handled by the event queue." While other options might have some truth in different contexts, the critical issue highlighted for microtasks is the starvation of the event queue.
Just read this? Test yourself on what you have been reading.
Read the original → dart.dev
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on dart — each one lists the topics its interview covers.
See open roles