What are Isolates?
In Dart, all code runs in an isolate — an independent worker with its own memory heap. Unlike threads in other languages, isolates don't share memory; they communicate only by passing messages (copies of data) through SendPort and ReceivePort. This eliminates race conditions and makes concurrency safe.
Why Isolates?
Dart's event loop is single-threaded. CPU-heavy work (image processing, encryption, parsing large JSON) blocks the event loop and freezes your UI. Offload such work to a separate isolate to keep your main isolate responsive.
Spawning an Isolate
import 'dart:isolate';
void heavyWork(SendPort sendPort) {
// This runs in a separate isolate
int sum = 0;
for (int i = 0; i < 1000000000; i++) sum += i;
sendPort.send(sum);
}
Future<void> main() async {
var receivePort = ReceivePort();
await Isolate.spawn(heavyWork, receivePort.sendPort);
var result = await receivePort.first;
print('Sum: $result');
receivePort.close();
}
Isolate.run (Dart 2.19+)
Isolate.run() is the simplest API — spawn, run, get result, and the isolate is automatically cleaned up:
import 'dart:isolate';
List<int> findPrimes(int limit) {
var primes = <int>[];
for (int n = 2; n <= limit; n++) {
bool isPrime = true;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) { isPrime = false; break; }
}
if (isPrime) primes.add(n);
}
return primes;
}
Future<void> main() async {
print('Finding primes...');
var primes = await Isolate.run(() => findPrimes(100000));
print('Found $${primes.length} primes');
print('First 10: $${primes.take(10).toList()}');
}
Two-way Communication
import 'dart:isolate';
void worker(SendPort mainSendPort) async {
var workerPort = ReceivePort();
mainSendPort.send(workerPort.sendPort); // send back our port
await for (var message in workerPort) {
if (message == 'STOP') break;
var result = message * 2; // process message
mainSendPort.send(result);
}
}
Future<void> main() async {
var mainPort = ReceivePort();
await Isolate.spawn(worker, mainPort.sendPort);
var messages = mainPort.asBroadcastStream();
SendPort workerSendPort = await messages.first;
for (var n in [1, 2, 3, 4, 5]) {
workerSendPort.send(n);
var result = await messages.first;
print('$n * 2 = $result');
}
workerSendPort.send('STOP');
mainPort.close();
}
Output:1 * 2 = 2
2 * 2 = 4
3 * 2 = 6
4 * 2 = 8
5 * 2 = 10
🧠 Quiz
1. How do isolates communicate in Dart?
- A) Shared memory variables
- B) Global state
- C) By passing message copies through SendPort/ReceivePort ✅
- D) Through synchronous function calls
2. What is the simplest way to run code in an isolate (Dart 2.19+)?
- A) Isolate.spawn
- B) Isolate.run ✅
- C) Thread.start
- D) compute()
Summary
Isolates are Dart's concurrency model — independent workers with no shared memory, communicating via message passing. Use Isolate.run() for one-off tasks (simplest), Isolate.spawn() for long-running workers. Pass data via SendPort/ReceivePort. Use isolates for CPU-intensive work to keep the main event loop responsive.