Flutter how to perform object-detection in an isolate using TensorFlow?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Running object detection in a Flutter isolate is a good way to keep the UI responsive when inference and image preprocessing are expensive. The main rule is that isolates do not share memory, so you should send plain transferable data such as image bytes or file paths, create the TensorFlow Lite interpreter inside the worker isolate, and send lightweight detection results back to the UI isolate.
Why Use An Isolate At All
Camera frames, image resizing, and TensorFlow Lite inference can easily block the main isolate if everything runs on the UI thread. That shows up as dropped frames, delayed gestures, and stuttering previews.
An isolate helps because:
- preprocessing can run off the UI isolate
- inference can run off the UI isolate
- only the final result comes back to the screen layer
This does not make the model itself magically faster, but it prevents heavy work from freezing the interface.
Keep The Data Transfer Simple
Do not try to send widget references, controller objects, or complex plugin state across isolates. Send only serializable or transferable data such as:
- a model path
- image bytes
- width and height
- plain maps or lists of results
A simple message type:
That kind of object is easy to reason about and does not depend on UI-layer objects.
Spawn A Worker Isolate
A basic isolate setup looks like this:
This creates a long-lived worker isolate. That is usually better than spawning a fresh isolate for every camera frame.
Create The Interpreter Inside The Worker
The interpreter should be initialized inside the isolate that uses it.
This matters because many problems come from trying to share interpreter state or plugin objects across isolates. Keep the worker self-contained.
Preprocess Before Inference
Object detection models usually expect resized and normalized tensors, not raw camera bytes.
A placeholder preprocessing function might look like this:
This example only shows structure, but in a real app you would:
- decode the image bytes
- resize to the model input size
- convert color channels as needed
- normalize pixel values
The more camera frames you process, the more valuable it becomes to keep this work in the isolate too.
Return Lightweight Detection Results
Do not send giant intermediate tensors back to the UI isolate if the screen only needs boxes and labels.
A simple result type:
Then convert raw model output into a list of DetectionResult objects inside the worker and send only that list back.
This keeps the message traffic smaller and the UI logic simpler.
For Repeated Camera Frames, Reuse The Worker
If the app performs live object detection, do not repeatedly spawn and tear down isolates for each frame. Start one worker, initialize the interpreter once, and send requests through a port.
That avoids repeated model loading, which can be more expensive than the inference itself.
It also makes backpressure easier to manage. If frames arrive too quickly, you can decide to:
- drop old frames
- keep only the most recent frame
- throttle detection frequency
That is usually necessary for a stable real-time UX.
Common Pitfalls
The biggest mistake is trying to share interpreter state or UI objects between isolates. Isolates do not share memory, so each worker should own its own runtime objects.
Another mistake is sending heavy image objects or plugin-specific state across isolate boundaries instead of plain bytes and metadata.
People also forget that preprocessing is often as expensive as inference. Moving only the model call to an isolate may still leave the UI thread overloaded.
Finally, spawning a fresh isolate per frame is usually too expensive for live camera scenarios. Reuse one worker isolate and one interpreter.
Summary
- Use an isolate to keep TensorFlow Lite preprocessing and inference off the Flutter UI isolate.
- Send plain transferable data such as image bytes, dimensions, and simple result objects.
- Create the interpreter inside the worker isolate instead of trying to share it.
- Reuse a long-lived worker for repeated detection tasks such as camera frames.
- Keep the response payload small by returning only detection boxes, labels, and scores.

