Skip to content

Beginner · Async Dart and packages · topic 11 of 50 · 25 min

Isolates for heavy work

Explanation

async/await keeps the app responsive while waiting, but heavy CPU work (parsing a huge JSON, processing an image) still runs on the main isolate and causes jank. An isolate is a separate worker with its own memory that communicates only by messages. Use Isolate.run (or Flutter's compute) to run a heavy function in the background and get its result back.

Waiting versus working

There are two kinds of slow. Waiting (for a network or a file) uses no CPU; async/await handles it perfectly on one thread. Working (calculating, parsing, compressing) uses the CPU continuously. While the main isolate is busy working, it cannot draw frames or respond to taps.

Flutter aims to draw a new frame about every 16 milliseconds (60 frames per second; even faster on 90 or 120 Hz screens). If one piece of work takes 200 ms on the main isolate, about a dozen frames are missed and the user sees the app stutter, called jank.

What is an isolate?

An isolate is Dart's unit of concurrency: an independent worker with its own memory and its own event loop. Isolates do not share memory, so there are no data races between them; they communicate by sending messages (copies of data). Your app's code normally runs on the main isolate.

Think of it like this: Isolates are like separate kitchens in a big restaurant. Each kitchen has its own staff and ingredients, so cooks never bump into each other. To share work, one kitchen sends a written order slip to another and gets the finished dish back.

Isolate.run

dart
import 'dart:convert';
import 'dart:isolate';

List<dynamic> parseHugeJson(String text) => jsonDecode(text) as List<dynamic>;

Future<void> main() async {
  final bigText = '[${List.filled(200000, '{"id":1,"name":"item"}').join(',')}]';
  final items = await Isolate.run(() => parseHugeJson(bigText));   // runs on a new isolate
  print('Parsed ${items.length} items');                              // Parsed 200000 items
}
Isolate.run (Dart 2.19+) starts an isolate, runs the function, returns its result and shuts the isolate down.

In Flutter you will also see compute(function, argument) from the foundation library, which does the same job and also works on the web (where it runs on the main thread, because the web does not support isolates in the same way).

When do you need it?

TaskIsolate needed?
Calling an API with httpNo: it is waiting, async is enough
Parsing a small JSON response (a few KB)No: it is fast
Parsing a multi-megabyte JSON fileOften yes
Resizing or filtering a photo in DartYes
Searching or sorting tens of thousands of itemsMaybe: measure first

Rules of thumb

  • Measure first with Flutter DevTools (module 9). Do not move everything into isolates "just in case".
  • The function you run must be self-contained: it gets its input as an argument (copied) and returns a result (copied). It cannot touch your widgets or state.
  • Sending very large objects between isolates costs copying time; send what you need.

Common mistakes

  • Using isolates for network calls: unnecessary; they are already asynchronous.
  • Trying to update UI or global state from inside the isolate function: it has its own memory.
  • Expecting isolates to speed up small work: starting one has a cost.
  • Blocking the UI with a long synchronous loop and blaming Flutter. Move the loop to an isolate.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Isolates for heavy work · 1/6

Waiting ≠ working

Waiting is handled by async. Heavy working, like parsing a huge file, still blocks the main isolate.

Prefer a video by a teacher? Find free videos on “dart isolates isolate.run flutter compute jank heavy work” on YouTube ↗

In real life: Importing a large product catalogue

A wholesale distributor's app downloads a 15 MB JSON catalogue of 80,000 products each morning. Parsing it on the main isolate froze the screen for two seconds. Moving jsonDecode and the mapping into Isolate.run keeps the progress animation smooth, and the parsed list comes back ready to save in the local database.

dart
import 'dart:isolate';

Future<int> countExpensive(List<int> prices) {
  return Isolate.run(() => prices.where((p) => p > 1000).length);
}

Future<void> main() async {
  final prices = List.generate(500000, (i) => i % 2000);
  print(await countExpensive(prices));   // 249750
}
The list is copied to the isolate, the count comes back.

Practice (0/3 done)

Task 1 · Question

Which task most needs an isolate?

Task 2 · Question

Why can an isolate function not change your widget's state directly?

Task 3 · Practice

Write a function that counts the prime numbers below 3,000,000 with a simple loop. Time it on the main isolate, then run it with Isolate.run and time it again while a periodic Timer prints "tick" every 100 ms. Note what happens to the ticks in each case.

Quick quiz

Question 1

1.What is jank?

Question 2

2.How do isolates communicate?

Question 3

3.Which API runs one function on a new isolate and returns its result?

Question 4

4.Does an http.get call need an isolate?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is jank?

Answer: Visible stutter caused by missed frames

Long main-isolate work causes it.

How do isolates communicate?

Answer: Messages (copied data)

They have separate memory.

Which API runs one function on a new isolate and returns its result?

Answer: Isolate.run

Available since Dart 2.19.

Does an http.get call need an isolate?

Answer: No; it is asynchronous waiting, not CPU work

async handles waiting.

What does an isolate NOT share with other isolates?Related

Answer: Memory

Isolates communicate by messages.

From Interview questions: Dart

What kind of work benefits most from async/await?Related

Answer: Waiting for network, disk or database (I/O)

async frees threads during I/O waits.

From async and await: waiting without blocking

What does an async function return?Related

Answer: A Future

async functions return Futures.

From Futures and async/await

async function f() { return 3; } What is f()?Related

Answer: A promise that fulfils with 3

async functions always return promises.

From async and await

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Async Dart and packages” before its exam: Packages and pub.
  2. Module 3 exam: Async Dart and packages · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Flutter setup and your first app. 50 topics left in the course before the final exam.

← Previous: Streams