Skip to content

Hot Reload

XWidget supports hot reload of fragments and value resources during a Flutter debug session. Edit an XML file in your IDE, save, and the running app updates immediately — no restart, no loss of app state.

Requirements

  • A debug build running in a Dart VM with service extensions enabled. This is the default for flutter run and IDE debug sessions.
  • An IDE plugin that supports XWidget hot reload:

What Gets Hot Reloaded

  • Fragment XML files under your configured fragmentsPath. Edits propagate as a full fragment replacement.
  • Value XML files under your configured valuesPath. Edits re-parse the file and merge new values into the active value bundle.

What does not hot reload:

  • Changes to Dart code — those go through Flutter's standard hot reload.
  • Changes to your inflater, icon, or controller specs — these require regeneration (xc generate) and a full restart.
  • Changes to xwidget_config.yaml — same; requires regeneration and restart.

How It Works

When you save a fragment or value file with a running debug session, the IDE plugin:

  1. Detects the save event.
  2. Opens a connection to the running app's Dart VM service.
  3. Calls one of two service extensions exposed by LocalResources:
    • ext.xwidget.updateFragment for fragment saves.
    • ext.xwidget.updateValues for value saves.
  4. Sends the new file content as a parameter.

The service extension handlers:

  1. Update the in-memory fragment or value bundle with the new content.
  2. Clear XWidget's parsed XML cache (for fragments).
  3. Call WidgetsBinding.instance.reassembleApplication(), which causes Flutter to rebuild the widget tree from the root.

The rebuilt tree sees the updated bundles and renders accordingly. Dependencies, app state, and navigation all persist.

Debouncing

The IDE plugins debounce saves at 200ms to coalesce rapid edits (e.g., auto-save on typing). A short status indicator in the IDE reflects the reload state.

Limitations

File additions and deletions require restart. Hot reload only handles content changes to files that existed when the app started. Adding a new fragment file or deleting an existing one is not picked up — restart the debug session.

Note

A fragment that's referenced via <fragment name="new_fragment"/> for the first time during hot reload will throw a "fragment not found" error unless that file existed at startup. The fix is a restart, not a bug in hot reload.

Cloud resources don't hot reload. CloudResources loads from a cloud-delivered bundle at startup and registers no file-watch service extensions — its asset-bundle fallback doesn't change that, because assets are a frozen snapshot that the IDE plugin can't inject into. Hot reload requires the running Resources instance to be a LocalResources. For local development, use LocalResources (the default) and hot reload works as described. To test fragment changes against a cloud project, deploy and publish to a staging channel (xc cloud deploy, then xc cloud publish -c staging) and restart.

Debug-only

The service extensions are gated on kDebugMode — they are never registered in release builds. The file watchers in the IDE plugins do nothing when no debug session is attached. There is no release-mode exposure of hot reload surfaces.

Troubleshooting

Saves don't trigger a reload. Confirm the debug session is running and the IDE status bar shows an active XWidget connection. Restarting the debug session re-registers the service extensions.

Changes load but app shows stale UI. Hot reload relies on reassembleApplication(), which rebuilds from the widget tree root. Widgets that bypass this (custom render objects, explicit keys that aren't invalidated, image caches) may show stale content. A full hot restart (R in flutter run) always resolves this.

Fragment parse error after reload. The updated file has a syntax error or references a widget that isn't registered. Fix the XML in the IDE and save again — reload is re-triggered.

See IntelliJ Plugin and VSCode Extension for installation.