In Flutter add-to-app, how does FlutterEngineGroup reduce the memory and startup cost of several Flutter screens, and what stays separate between its engines?
answer
- spawned engines share GPU context and fonts
- shared isolate group snapshot
- about 180 kB per extra instance
- each engine is its own Dart program
- talk through the host via channels
basics
~20 sEngines spawned from one FlutterEngineGroup share reusable resources — GPU context, font metrics and the isolate group snapshot — so each extra instance costs about 180 kB and starts faster. Each engine still runs its own isolate with separate Dart state.
solid answer
~50 sWhen a native app shows Flutter in several places at once or in a native→Flutter→native→Flutter stack, each place needs an engine. Constructing each `FlutterEngine` directly repeats the full cost. `FlutterEngineGroup` (Android and iOS) spawns engines that **share** the GPU context, font metrics and the isolate group snapshot; the docs put the incremental cost at about 180 kB per extra instance, with faster first render. Only the first engine in a group pays the normal cost, and as long as at least one spawned engine lives, later ones stay cheap; if all are destroyed, the next pays full price again. What stays separate: each engine runs its own isolate — its own heap, navigation stack and state — so engines cannot share Dart objects and communicate through the host with platform channels or Pigeon. On Android, `FlutterEngineGroupCache` plus `FlutterActivity.withNewEngineInGroup(id)` wire it up; on iOS, `makeEngineWithEntrypoint:libraryURI:`.
go deeper
Know that FlutterEngineGroup creates several Flutter engines more cheaply than constructing each FlutterEngine directly.
Explain what spawned engines share, the roughly 180 kB incremental cost, and the lifetime rules for the group and its engines.
Design multi-engine screens knowing each engine has its own isolate and state, and route shared data through the host with channels or Pigeon.
Weigh one long-lived engine against many grouped engines for a hybrid app's navigation, balancing memory, state retention and team modularity.
## When you need several engines On mobile, add-to-app is **multi-engine**: every simultaneously alive Flutter UI has its own `FlutterEngine`. That happens when: - the navigation stack mixes frameworks — native → Flutter → native → Flutter — and the earlier Flutter screen must keep its state; - one native screen shows several partial Flutter views at once, for example a loyalty card and a trip summary. Each engine is an independent Dart program with its own navigation stack, UI and state. That independence is useful for modularity, but constructing every engine directly costs full memory and start-up time each time. ## What FlutterEngineGroup shares Engines **spawned from the same `FlutterEngineGroup`** share reusable resources: - the GPU context; - font metrics; - the isolate group snapshot (the loaded Dart program). The Flutter docs describe the result as a low incremental memory cost of **about 180 kB** per additional Flutter instance, and a faster initial rendering latency. ## Lifetime rules | Situation | Cost of the next engine | |---|---| | First engine created from the group | Same as constructing a `FlutterEngine` directly | | At least one spawned engine still alive | Cheap: shares resources with the living ones | | All spawned engines destroyed | Full cost again, like the very first engine | | The group object itself destroyed | Existing engines keep working; no more cheap spawning | The **first** engine does not have to survive for later ones to share — only **some** engine from the group must be alive. And the very first engine per process, in any group, also pays the one-time Dart VM start. ## What stays separate Sharing is at the engine-resource level, not the Dart level: 1. Each engine runs its **own isolate**, so Dart objects, providers, caches and singletons are not shared. 2. Each engine has its **own navigation stack** and widget tree. 3. Engines talk to each other **through the host platform**, using platform channels or Pigeon; there is no direct Dart-to-Dart channel between them. Design consequence: put shared data — the signed-in user, loyalty balance — in the host or in a store every engine reads, not in a Dart singleton you expect all screens to see. ## Wiring it up Android: ```kotlin // Application.onCreate val group = FlutterEngineGroup(this) FlutterEngineGroupCache.getInstance().put("airline_group", group) // Launching a screen startActivity( FlutterActivity.withNewEngineInGroup("airline_group") .dartEntrypoint("loyaltyMain") .initialRoute("/points") .build(this) ) ``` Or create engines directly with `group.createAndRunEngine(context, dartEntrypoint)` and cache them. `FlutterFragment.withNewEngineInGroup` exists for fragments. iOS: create a `FlutterEngineGroup` with `initWithName:project:` and spawn engines with `makeEngineWithEntrypoint:libraryURI:`, then pass each to a `FlutterViewController`. A custom entrypoint such as `loyaltyMain` must be annotated in Dart so it is not tree-shaken: ```dart @pragma('vm:entry-point') void loyaltyMain() => runApp(const LoyaltyApp()); ``` ## Judgment calls - One pre-warmed engine reused across visits keeps state but holds memory while idle; a group of short-lived engines keeps each cheap but loses state when an engine is destroyed. - Several live engines still each hold their own Dart heap; 180 kB is the incremental fixed cost, not the whole cost of a screen with images and data. - Watch plugins that assume a single engine or a single instance: each engine creates its own plugin instances.
- Two Flutter screens from the same FlutterEngineGroup both need the signed-in user. Can they share a Dart singleton?No. Each engine runs its own isolate, so a Dart singleton exists once per engine. Keep the user in the host app or persistent storage and pass it to each engine through platform channels or Pigeon.
- Does destroying the FlutterEngineGroup stop the engines it spawned?No. Existing engines keep running; you only lose the ability to spawn further engines that share resources with them. Each engine must be destroyed on its own.
saying these in an interview costs you the question
- Engines in one FlutterEngineGroup share a single Dart isolate and heap.
- The first spawned engine must stay alive for later engines to share resources.
- Destroying the FlutterEngineGroup destroys every engine it spawned.
- Each extra engine in a group costs as much as a normally constructed one.
- Flutter engines can pass Dart objects to each other directly.