← Flutter Reference

What is BLoC in Flutter?

State Management · Intermediate

By Abdelrahman Saed — Senior Mobile Engineer. Last updated: 2026-08-10.

BLoC (Business Logic Component) is a reactive state management pattern for Flutter that separates business logic from presentation using streams. Events go in, states come out, and the UI never touches business logic directly — it reacts to state changes the way it reacts to any data source.

How it works

BLoC converts a stream of events (user actions, lifecycle signals, data fetches) into a stream of states (the data the UI renders). The bloc itself is a pure function — the same events in the same order always produce the same states — which makes it trivially testable.

The data flow is strictly one-directional:

Widget → Event → BLoC → State → Widget

A widget dispatches an event when the user interacts with it. The bloc receives the event, runs the business logic (calling repositories, transforming data, enforcing rules), and emits a new state. The widget rebuilds with the new state via StreamBuilder or BlocBuilder.

Here is a minimal counter bloc:

// Events
abstract class CounterEvent {}
class IncrementPressed extends CounterEvent {}
class DecrementPressed extends CounterEvent {}

// States
abstract class CounterState {}
class CounterInitial extends CounterState {
  final int count;
  CounterInitial(this.count);
}

// Bloc
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterInitial(0)) {
    on<IncrementPressed>((event, emit) {
      emit(CounterInitial((state as CounterInitial).count + 1));
    });
    on<DecrementPressed>((event, emit) {
      emit(CounterInitial((state as CounterInitial).count - 1));
    });
  }
}

At iStoria (5M+ users, 50+ modules), every feature follows the same pattern: events define every user intent, states define every UI configuration, and the bloc mediates. The result is that a new engineer can read any feature's event/state classes and understand its full behaviour without touching the UI layer.

When to use it

Choose BLoC when:

  • Your app has complex state flows with multiple interacting data sources (API, local database, sync engine).
  • You need strict testability — every state transition is a testable unit, and no business logic lives in widgets.
  • A team of engineers works on the same codebase — BLoC's enforced structure prevents the "every screen does it differently" problem.
  • You want traceability — bloc_concurrency and hybrid_bloc logging let you replay any state transition.

Skip BLoC when:

  • The app is small (a few screens, no complex state) — the boilerplate isn't worth it; use Cubit or Riverpod instead.
  • Your team has no state management experience — BLoC's learning curve is steeper than Cubit or Riverpod, and misusing it (e.g. putting business logic in event transformers) creates more problems than it solves.

Strengths

  • Strict separation of business logic from UI — no logic leaks into widgets
  • Every state transition is unit-testable without a widget tree
  • Excellent tooling — the bloc library provides devtools, concurrency control, and replay
  • Scales to large teams — every feature follows the same predictable pattern
  • Events create an audit log of user intent — you can trace exactly what happened

Tradeoffs

  • Significant boilerplate — every feature needs separate event, state, and bloc classes
  • Steeper learning curve than Cubit or Riverpod
  • Overkill for simple screens — a counter or a toggle doesn't need an event class
  • Can lead to analysis paralysis on event design — teams overthink event granularity

Alternatives

  • Cubit — Cubit is a lightweight variant of the BLoC pattern that replaces events with direct method calls. Simpler than BLoC, but the same testability and reactive model.
  • Riverpod — Riverpod is a reactive caching and state management framework for Flutter that improves on Provider with compile-time safety, no BuildContext dependency, and auto-dispose.
  • GetX — GetX is an all-in-one Flutter framework providing state management, dependency injection, route management, and utilities. Popular for rapid prototyping, controversial for production.

Comparisons

Related articles

Related case studies

FAQ

What is the difference between BLoC and Cubit?

Cubit is a simplified version of BLoC that replaces event classes with direct method calls. Instead of dispatching an IncrementPressed event, you call increment(). Cubit is better for simple state; BLoC is better when you need the event trail or complex event-to-state transformations.

Is BLoC still recommended in 2026?

Yes. BLoC remains the most battle-tested state management pattern for large Flutter apps. It is the default at companies like iStoria (5M+ users) and is actively maintained with the flutter_bloc package. For new apps, Cubit (BLoC without events) is often a better starting point, migrating to full BLoC when event granularity is needed.

Does BLoC work with offline-first apps?

Yes — BLoC pairs naturally with offline-first architectures. The bloc receives events from the UI, calls repository methods (which read from the local database first), and emits state. Whether the data came from the local Drift database or a PowerSync sync round-trip is transparent to the bloc.


Available for hire. Abdelrahman Saed is a Senior Mobile Engineer (Flutter) — open to full-time, fractional, contract, or advisory work. Hire me →

Book a 20-minute call · Download the CV (PDF) · See how I work