Dart's Shared-Memory Multithreading Lands with IsolateGroupBound
This removes a fundamental interop tax for Flutter apps that embed native audio engines, UI frameworks, or other C/C++ libraries. Native threads can now call Dart synchronously without the overhead of copying data or the complexity of routing through a specific isolate's event loop.
Dart's long-running effort to add shared memory to isolates has reached a concrete milestone. The `NativeCallable.isolateGroupBound` API, now in Dart 3.12.2, allows native code on any thread to synchronously execute a Dart callback within an isolate group, without binding to a particular isolate. This callback can only access static or top-level state explicitly marked as shared via `@pragma('vm:shared')`.
Shared state is currently limited to deeply immutable types, `TypedData`, `Struct`, and closures meeting strict capture constraints. Ordinary mutable Dart objects like `List` and `Map` remain isolate-local. The new `dart:concurrent` library provides `Mutex` and `ConditionVariable` to manage concurrent access to shared mutable binary data, since the VM does not guarantee sequential consistency for those writes.
The design solves two persistent pain points: the high cost of copying large object graphs between isolates, and the friction of native threads needing to understand Dart's isolate model. A future goal is for Dart AOT code to behave like a standard C library, where any native thread can call exported Dart symbols directly. The current implementation uses a hybrid of compile-time and runtime checks, and `dart:async` APIs like `Future` and `Stream` are unavailable in this context, making it best suited for short, synchronous FFI callbacks.
By restricting shared state to a narrow set of trivially shareable types instead of opening up arbitrary Dart objects, the Dart team sidesteps the hardest concurrency problems while still solving the most expensive interop bottlenecks.
The hybrid checking approach—compile-time for field declarations, creation-time for callback captures, and runtime for deep call chains—is a pragmatic compromise that avoids a massive type-system overhaul but leaves a class of bugs that only surface in production.
Third-party ecosystem compatibility is the biggest hidden risk. Libraries written under the old isolate model freely use static state, and none of them were designed for an execution context where that state is off-limits.
Making `dart:io` eventually implementable in pure Dart is a signal that the team sees this shared-memory model as foundational enough to rewrite core platform libraries on top of it.