If profiling shows that sorting is blocking Flutter’s UI isolate and causing jank, move the CPU-heavy transformation to a worker isolate. For a one-off sort, use Flutter’s compute or Dart’s Isolate.run; for frequent sorts, consider a persistent worker only after measuring its benefit. Neither approach guarantees a faster sort: isolate startup and message transfer have costs, and Flutter web’s compute runs on the main thread.
When should you move sorting to another isolate?
Start by profiling the affected interaction or animation. Flutter recommends isolates for computations that take long enough to cause UI jank; an expensive sort on the main isolate can delay input handling and frame work. Moving that computation to a separate isolate allows the main isolate to continue servicing UI work while the sort runs.
An isolate is not a blanket optimization for every list. Creating a worker and transferring its input and result take time, so the crossover depends on the data and target devices. Flutter’s guidance does not establish a sorting-specific item-count threshold or speedup. Measure on representative hardware rather than assuming a list is large enough to benefit.
Flutter’s Performance FAQ addresses poor animations caused by an expensive Dart async function blocking the UI thread and recommends compute for that kind of work.
#1 Best Overall
Choose an isolate pattern for your sorting workload
| Approach | Best fit | Trade-off |
|---|---|---|
compute |
A one-off or occasional background transformation in Flutter | Convenient Flutter API; on mobile and desktop it uses a short-lived isolate pattern. On web, the computation runs on the main thread. |
Isolate.run |
A one-off or occasional transformation using Dart’s direct API | Runs a closure in a short-lived isolate on supported mobile and desktop targets; captured values and the result must be sendable. |
Persistent worker with Isolate.spawn and ports |
Repeated computation where avoiding repeated worker setup may matter | Requires managing the worker lifecycle and message protocol. Measure whether that complexity pays off for your workload. |
Flutter documents compute(fun, message) as equivalent to Isolate.run(() => fun(message)) on mobile and desktop. See Flutter’s concurrency and isolates guide and the Isolate.run API documentation.
Run a one-off sort with compute
Put the transformation in a top-level or otherwise suitable worker function, pass the data explicitly, and await the returned list:
Rank #2
import 'package:flutter/foundation.dart';
List<Item> sortItems(List<Item> items) {
items.sort((a, b) => a.key.compareTo(b.key));
return items;
}
final sorted = await compute(sortItems, items);
This is an illustrative shape, not project-tested code. Define Item and its fields for your application, and ensure the arguments and result can cross the isolate boundary on the target runtime. Flutter’s background parsing recipe demonstrates compute and describes message constraints.
Account for mutation and equal sort keys
List.sort changes the list
List.sort sorts its receiver in place. If the caller needs the original list unchanged, make a copy before sorting or construct a worker-specific representation. The Dart List.sort documentation also notes that the sort is not guaranteed to be stable.
Recommended Free Tools
Make tie ordering explicit when it matters
If items with equal keys must retain their input order, include the original index and use it as a tie-breaker after comparing the primary key. Do not rely on equal comparisons preserving the input order.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Respect isolate boundaries and Flutter limitations
Isolates have separate memory and communicate by messages; they do not share mutable objects. Pass only supported, sendable input and return a sendable result. With Isolate.run, a closure can capture more state than intended, increasing memory use or failing if captured objects cannot be sent. Keep the worker focused on data transformation and pass its inputs explicitly.
Quick Recap
Best Value
Rank #4
- Do not send complex values that are not supported across the boundary; Flutter’s cookbook warns that values such as a
Futureorhttp.Responsecan cause errors. - Keep widget work and asset loading out of the worker. A spawned isolate cannot perform widget work or access
rootBundle; those tasks remain tied to the main isolate. - On Flutter web,
computedoes not move sorting to a background thread under Flutter’s documented behavior. It can preserve a common code shape across platforms, but it does not remove main-thread sorting work on web.
Implement and verify the change
- Profile the jank. Confirm that CPU-bound sorting is the work delaying frames, rather than assuming that the sort is responsible. Flutter’s performance best practices also advise against expensive work in frequently called build methods.
- Extract a focused worker function. Give it explicit input and output; leave UI state, widgets and asset access on the main isolate.
- Choose mutation behavior. Decide whether the worker may sort a private list in place or should return a separately built representation.
- Select the worker pattern. Use
computeorIsolate.runfor occasional work. For repeated sorts, profile whether a persistent worker is worth its lifecycle and messaging complexity. - Test correctness and application behavior. Check the comparator, equal-key handling, empty and large inputs, and error propagation. Decide how the UI should handle a result that arrives after the relevant screen or request has changed; cancellation and stale-result policy depend on the application.
- Profile on target devices and platforms. Compare the user-visible behavior and total work, including setup and data transfer. There is no published sorting-specific speedup or item-count threshold in the cited Flutter guidance.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

