Start Debugging

Provider vs Riverpod vs Bloc für State Management in Flutter 2026

Wählen Sie Riverpod für die meisten neuen Flutter-Apps in 2026. Greifen Sie zu Bloc, wenn ein großes Team eine erzwungene ereignisbasierte Struktur will, und behalten Sie Provider nur für Legacy-Code.

Wenn Sie 2026 eine neue Flutter-App starten und sich nicht zwischen Provider, Riverpod und Bloc entscheiden können, lautet die kurze Antwort Riverpod. Mit Riverpod 3.3.1 (die 3.0-Linie erschien am 2025-09-10) ist es sicher zur Kompilierzeit, ohne BuildContext testbar, und der Pfad über Codegenerierung beseitigt fast das gesamte Boilerplate, das früher das Hauptargument dagegen war. Greifen Sie zu Bloc (flutter_bloc 9.1.1), wenn Sie ein großes Team haben, das von einem strengen ereignisbasierten Vertrag und einer nachvollziehbaren Zustandshistorie profitiert. Behalten Sie Provider (6.1.5) nur, wenn Sie ihn bereits in einer Codebasis haben oder jemandem das zugrunde liegende InheritedWidget-Modell beibringen. Alle Beispiele hier verwenden Flutter 3.44 und Dart 3.12.

Die drei Pakete sind nicht dieselbe Art von Werkzeug

Bevor man sie vergleicht, hilft es zu sehen, dass diese Bibliotheken überlappende, aber unterschiedliche Probleme lösen.

Provider ist ein dünner, gut gemachter Wrapper über Flutters eigenem InheritedWidget. Er macht Dependency Injection und die Weitergabe von Rebuilds, und im Wesentlichen war es das. Die Zustandsklasse ist meist ein ChangeNotifier, den Sie von Hand schreiben. Es ist das Paket, zu dem die offizielle Flutter-Dokumentation griff, als sie ein didaktisches Beispiel brauchte, weshalb so viele Tutorials es verwenden.

Riverpod ist das, was der Autor von Provider als Nächstes baute, gezielt um die strukturellen Probleme von Provider zu beheben: die ProviderNotFoundException zur Laufzeit, die Abhängigkeit von der Position des Widgets im Baum und die Unmöglichkeit, den Zustand aus reinem Dart zu lesen. Riverpod-Provider leben außerhalb des Widget-Baums, sind also von überall erreichbar und werden zur Kompilierzeit aufgelöst.

Bloc ist zuerst ein Muster und dann ein Paket. Es drängt Sie dazu, jede Änderung als explizites Ereignis zu modellieren, das in eine Komponente fließt und einen neuen unveränderlichen Zustand erzeugt. Diese Zeremonie ist genau der Punkt: In einem großen Team macht eine erzwungene Event -> Bloc -> State-Pipeline das Verhalten vorhersehbar und überprüfbar.

Funktionsmatrix

FunktionProvider 6.1.5Riverpod 3.3.1Bloc 9.1.1
GedankenmodellInheritedWidget + ChangeNotifierProvider außerhalb des BaumsEreignisbasiert, unveränderliche Zustände
Sicherheit zur KompilierzeitNein (Suche zur Laufzeit)JaJa
Braucht BuildContext zum LesenJaNeinNein (über context.read oder direkt)
BoilerplateGeringGering mit CodegenHoch
TestbarkeitBraucht Widget-PumpingReines Dart, kein Widget-BaumReines Dart, bloc_test-Helfer
Async- / LadezustandManuellAsyncValue, eingebautManuelle Zustände oder emit
Automatischer Retry bei FehlernNeinJa (seit 3.0)Nein
Nachverfolgbarkeit des ZustandsSchwachMittelStark (jeder Übergang beobachtbar)
LernkurveSanftModeratSteil
Beste EignungLegacy, TutorialsDie meisten neuen AppsGroße Teams, komplexe Abläufe

Die wichtigste Zeile ist “Sicherheit zur Kompilierzeit”. Ein falsch konfigurierter Provider wirft ProviderNotFoundException zur Laufzeit, oft nur auf dem Bildschirm, wo er fehlt. Riverpod und Bloc bringen diese Fehlerklasse ans Licht, bevor die App läuft.

Derselbe Zähler in allen dreien

Ein Zähler ist klein genug, um die Ergonomie direkt zu vergleichen. Beachten Sie, wie viel Code jeder braucht und wo der Zustand lebt.

Provider

// Flutter 3.44, provider 6.1.5
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

// Register it above the widgets that need it.
ChangeNotifierProvider(
  create: (_) => CounterModel(),
  child: const CounterPage(),
);

class CounterPage extends StatelessWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context) {
    final count = context.watch<CounterModel>().count;
    return Scaffold(
      body: Center(child: Text('$count')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<CounterModel>().increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

Beachten Sie die Abhängigkeit von context. Wird CounterPage ohne einen ChangeNotifierProvider darüber gerendert, wirft context.watch<CounterModel>() zur Laufzeit.

Riverpod

// Flutter 3.44, flutter_riverpod 3.3.1, riverpod_annotation
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'counter.g.dart';

@riverpod
class Counter extends _$Counter {
  @override
  int build() => 0;

  void increment() => state++;
}

class CounterPage extends ConsumerWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Scaffold(
      body: Center(child: Text('$count')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(counterProvider.notifier).increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

Der counterProvider wird generiert und ist global erreichbar. Es gibt keine Baumposition, die man falsch machen könnte, und ref wird zur Kompilierzeit aufgelöst. Umhüllen Sie die App einmal mit ProviderScope, und Sie sind fertig.

Bloc

// Flutter 3.44, flutter_bloc 9.1.1, equatable
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

// Events
sealed class CounterEvent {}
class Increment extends CounterEvent {}

// Bloc: Event in, int state out.
class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<Increment>((event, emit) => emit(state + 1));
  }
}

class CounterPage extends StatelessWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (_) => CounterBloc(),
      child: Builder(
        builder: (context) => Scaffold(
          body: Center(
            child: BlocBuilder<CounterBloc, int>(
              builder: (context, count) => Text('$count'),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(Increment()),
            child: const Icon(Icons.add),
          ),
        ),
      ),
    );
  }
}

Bloc ist für einen Zähler am ausführlichsten, und dieser Vergleich ist ihm gegenüber unfair: Der Wert von Bloc zeigt sich, wenn es zwanzig Ereignisse und zehn Zustände gibt, nicht eines. Das Increment-Ereignis ist ein Eintrag in der Historie Ihrer App. Mit einem angehängten BlocObserver können Sie jeden Übergang protokollieren, was genau das ist, was Sie beim Debuggen eines komplexen Bildschirms wollen.

Wann Sie Riverpod wählen sollten

Ein Vorbehalt: In Riverpod 3.0 wurden StateProvider, StateNotifierProvider und ChangeNotifierProvider nach package:riverpod/legacy.dart verschoben. Neuer Code sollte die oben gezeigten Klassen Notifier und AsyncNotifier verwenden, idealerweise mit Codegenerierung über @riverpod.

Wann Sie Bloc wählen sollten

Wann Sie Provider wählen sollten

Was Provider 2026 nicht sein sollte, ist die Standardwahl für eine neue, nicht triviale App. Das Suchmodell zur Laufzeit ist genau das Problem, zu dessen Beseitigung Riverpod gebaut wurde.

Die Stolpersteine, die für Sie entscheiden

Einige Einschränkungen überstimmen die persönliche Vorliebe.

Den Zustand aus Nicht-Widget-Code lesen. Wenn Ihre Architektur eine Service- oder Repository-Schicht hat, die den App-Zustand direkt lesen muss, ist Provider praktisch raus. Er braucht einen BuildContext. Riverpod und Bloc erlauben beide das Lesen des Zustands aus reinem Dart, was die Entscheidung meist von selbst klärt.

Teamgröße und Review-Kultur. In einem Solo-Projekt oder einem kleinen Team ist Blocs Zeremonie Reibung mit wenig Ertrag, und Riverpod gewinnt bei der Geschwindigkeit. In einem 15-köpfigen Team, wo Konsistenz über Funktionen hinweg mehr zählt als Codezeilen, ist Blocs Starrheit eine Funktion, keine Kosten.

Disziplin bei unveränderlichem Zustand. Sowohl Bloc als auch das moderne Riverpod drängen Sie zu unveränderlichen Zustandsobjekten. Wenn Ihr Team mit versiegelten Klassen und Wertgleichheit vertraut ist (siehe Dart Records vs Freezed-Klassen für die Modellierungsoptionen), passen beide. Wenn Sie eine große Codebasis auf veränderlichen ChangeNotifier-Objekten haben, ist der günstigste Weg vielleicht, bei Provider zu bleiben, bis eine Funktion tatsächlich mehr braucht.

Vorhandene Async-Muster. Riverpods AsyncValue ist der aufwandsärmste Weg, Laden, Daten und Fehler aus einer einzigen Wahrheitsquelle zu rendern. Wenn Ihre Bildschirme größtenteils Async-Datenabrufe sind, ist das allein schon ein starker Grund, es zu wählen.

Die Empfehlung, noch einmal

Verwenden Sie für die meisten neuen Flutter-Apps in 2026 Riverpod 3.3.1 mit Codegenerierung. Sie erhalten Sicherheit zur Kompilierzeit, kontextfreie Lesezugriffe, erstklassiges Async und die Resilienz-Funktionen von 3.0, bei Boilerplate-Kosten, die Codegen nahe an Provider heranbringt.

Wählen Sie Bloc 9.1.1, wenn eine erzwungene ereignisbasierte Struktur und eine vollständig nachverfolgbare Zustandshistorie Ihrem Team mehr wert sind als Knappheit, was bei großen Teams und komplexen Abläufen meist zutrifft. Verwenden Sie Cubits innerhalb einer Bloc-App für die Bildschirme, die keine vollständigen Ereignisse brauchen.

Behalten Sie Provider 6.1.5 für Legacy-Apps, Lehre und triviale Bildschirme, aber greifen Sie nicht standardmäßig in einem neuen, nicht trivialen Projekt dazu. Die entscheidende Frage ist selten “welcher hat den schönsten Zähler”, sondern “lese ich Zustand außerhalb von Widgets, wie groß ist mein Team und wie viel Async habe ich?”. Beantworten Sie diese drei, und die Wahl trifft sich meist von selbst. Wenn Sie Flutter gegen ganz andere Stacks abwägen, zoomt unser Vergleich von Flutter vs React Native vs MAUI eine Ebene heraus. Und was auch immer Sie wählen, denken Sie daran, Ihre Controller freizugeben, denn keine State-Management-Bibliothek räumt diese für Sie auf.

Quellen

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Zurück