Dart & Flutter  ·  v0.34.0

Reactive state,
the way it should feel.

Live Cells brings true reactivity to your Dart & Flutter data layer. Declare cells, compose them, and let your UI respond automatically—no boilerplate, no manual listeners, no dispose().

Get Started View on pub.dev
flutter pub add live_cells

Built for Flutter's
reactive model

Everything you need to write expressive, composable state logic without fighting the framework.

Automatic propagation

Observers are notified automatically when cell values change. Define a computed cell once and it stays in sync forever.

Two-way data flow

Unique among reactive libraries: data can flow in both directions. Bind a text field to a number cell with a single line.

🗑

No dispose() calls

Cells manage their own lifecycle. No more forgetting to remove listeners or call dispose()—memory cleans itself up.

🧩

Composable expressions

Write a + b and get a cell whose value is always the sum. Functional composition, no listener wiring.

🎛

Widget integration

Drop-in reactive widgets—LiveSwitch, LiveTextField, CellWidget—bind directly to cells with no state management ceremony.

💾

State restoration

Persist and restore app state with minimal boilerplate. Cells that survive process death, with no extra wiring.

Less ceremony,
more clarity

See the difference when reactive state is a first-class citizen of your data layer.

Without Live Cells ValueNotifier
final a = ValueNotifier<int>(0);
final b = ValueNotifier<int>(1);
late final sum = ValueNotifier<int>(0);
// Wire listeners manually
void _updateSum() {
  sum.value = a.value + b.value;
  print('${a.value} + ${b.value} = ${sum.value}');
}
// Remember to add AND remove
a.addListener(_updateSum);
b.addListener(_updateSum);
...
@override
void dispose() {
  a.removeListener(_updateSum);
  b.removeListener(_updateSum);
  a.dispose();
  b.dispose();
  sum.dispose();
  super.dispose();
}
With Live Cells MutableCell
final a = MutableCell(0);
final b = MutableCell(1);
// Reactive expression — just works
final sum = a + b;
// Observe — no manual wiring
ValueCell.watch(() {
  print('${a()} + ${b()} = ${sum()}');
});
// No dispose() needed.
// Ever.

One abstraction
to learn

The cell is the only primitive. Master it and you have mastered the library.

// Mutable cells

The entry point to reactivity. Set a value; observers fire automatically.

final count = MutableCell(0);
count.value++;   // triggers observers

// Computed cells

Derive state from other cells with plain expressions or ValueCell.computed.

final doubled = count * 2.cell;
// or
final label = ValueCell.computed(
  () => 'Count: ${count()}',
);

// Two-way flow

Bind a numeric cell to a text field. Changes flow both ways automatically.

final n = MutableCell<num>(0);

LiveTextField(
  content: n.mutableString(),
);

// Widget binding

Rebuild only the widgets that need to—no setState, no provider lookup.

final count = MutableCell(0);
final isEnabled = MutableCell(true);

...          

CellWidget.builder(() =>
  Text('${count()}')
);

...

LiveSwitch(value: isEnabled);

// Async cells

Await futures held in cells. Computed cells propagate loading state too.

final isLoading = (c1, c2).isCompleted.not();

final sum = ValueCell.computed(() {
  final (a, b) = (c1, c2).wait();
  return a + b;
});

// Error handling

Exceptions propagate through cell chains. Handle them where it makes sense.

final str = MutableCell('0');

final n = ValueCell.computed(
  () => int.parse(str()),
);

final valid = (n > 0.cell)
  .onError(false.cell);

Beyond ChangeNotifier

Live Cells solves the friction points you've accepted as normal in Flutter state management.

Unopinionated

No forced architecture. Use as much or as little of Live Cells as you need. Integrate incrementally.

Drop-in for ValueListenable

The .listenable property wraps any cell as a ValueListenable—use it wherever Flutter expects one.

Previous value access

Need the last value of a cell? Just use cell.previous—it's a cell too.

Code-gen for your types

live_cell_extension generates property accessors so you can use cell syntax on your own model classes.

Used by developers building with Flutter

Using Live Cells in your app? Open a PR to add it here →

Ready to make your state actually reactive?

Read the docs → GitHub

Up and running
in minutes

Three steps from zero to reactive Flutter app.

Add the dependency

flutter pub add live_cells — or add live_cells: ^0.34.0 to your pubspec.yaml.

Import & define cells

Import package:live_cells/live_cells.dart and declare your state as MutableCell instances at the top of your logic layer.

Bind to widgets

Wrap rebuilding UI in CellWidget.builder, or swap Flutter widgets for their Live* equivalents. Done.