Introducing Blooming: a reactive framework for Dart and Flutter

Hi Flutter folks,

I’m building Blooming, a reactive framework for Dart and Flutter, and would love to hear what you think.

What led me to Blooming

While building a Flutter UI authoring tool, I kept running into state-management problems and rebuilt the state-management layer several times. A turning point came when I explored Preact Signals and Signals.dart. I was especially drawn to the API design of computed: dependencies are connected dynamically based on the signals read during a computation, and those connections are updated when the reads change.

That idea resonated strongly with me, so I went back and redesigned the reactive pipeline I had already completed from the ground up. That redesign became Blooming.

How it works

Blooming’s core uses a two-phase push-dirty / lazy-pull graph. When a source changes, dependent nodes are marked dirty first; derived values are recomputed on demand, in dependency order. This is designed to prevent intermediate inconsistent values from being observed in diamond-shaped dependency graphs. Dependencies are declared explicitly with via(node), rather than discovered through ambient tracking.

Blooming Flutter connects the graph to Flutter’s widget tree. APIs such as bloom.build and composed let a small UI boundary observe reactive values and update independently of its surrounding widgets.

A few design choices

  • Three-state snapshots: Reactive values use Data, Empty, and Error states. The async UI helpers also support stale-while-revalidate behavior, preserving existing data while new data is being fetched.
  • Lifecycle-bound resource management: managed ties external resource creation, updates, and disposal to a reactive node’s lifecycle.
  • Graceful deactivation policies: When a node has no subscribers, its upstream connections and associated resources are normally torn down. Graceful controls when that deactivation and cleanup happen. Graceful.microtask defers teardown by one scheduler tick; Graceful.period(…) keeps the node and its upstream dependencies active for a specified duration.
  • Animations controlled from an ancestor: I built DurableAnimationController so an ancestor can own and control an animation without tying the controller to the state of the child that displays it. It can be used without StatefulWidget or TickerProviderStateMixin, with policies to resume, catch up to elapsed time, or reset when the UI becomes active again.
  • Transactional collection editing: BloomDraftController provides edit for reactive lists, sets, and maps. You modify a temporary draft, then commit it as an unmodifiable collection. Multiple changes produce at most one invalidation, and an edit with no net change produces none.

The workspace also includes collection extensions, lint rules, and testing packages.

Blooming is pre-1.0; its API and design are still evolving and may change substantially. I’d especially appreciate feedback on the usability and direction of the composed API, the lifecycle model, and whether this approach would fit real Flutter apps.

English isn’t my first language, so I used AI to help write this post in English. The project and the ideas behind it are mine.

Thanks for taking a look!

Have you seen BlocSignal? I also saw Signals (Rody’s package) to be a great data-dependency structure, but it was too flexible. So I added the riger of Bloc and Cubit to hold the core synchronous data in an app, relying on pure signals at the async edges.

EDIT: I reviewed your repo, and five items stood out as being useful to BlocSignal:

thanks for your package!

1 Like

Thanks for taking the time to read through Blooming and for sharing BlocSignal. I’ll take a closer look at it. It’s great to hear that some of Blooming’s ideas might be useful in your project. I appreciate you pointing out the features that stood out to you, and I’ll follow the linked issues with interest. Your perspective is helpful as I continue to evolve Blooming. :slightly_smiling_face:

1 Like