Riverpod vs Bloc 比較

少ないコードでコンパイル時の安全性を確保する、急速に進化するproviderアーキテクチャ

VS
Bloc

event/stateの流れを必須とする、成熟し大規模コミュニティを持つアーキテクチャ規約

10 分で読了Cross-Platform

クイック結論

「間違った選択」は存在しない――どちらも実績があり、MITライセンスだ。1〜5人の小規模チームで素早く反復開発するならRiverpod:ボイラープレートが少なく、コード生成は任意で、リリースペースも非常に活発(3.4.3、2026-09-03)。複数チームが関わり、監査可能なイベントフローが求められるエンタープライズプロジェクトならBloc:イベント/ステートの分離が必須で、BlocObserverもある。ただしflutter_blocの最新リリースは2025-05-02なので注視が必要だ。問うべきは「どちらが優れているか」ではなく、「規律をどこまで外部から強制すべきか」だ。

RiverpodBloc
結論をすべて読む

スコア比較

グラフを読み込み中...

詳細スコア

詳細スコア: Riverpod Bloc — カテゴリー別10点満点のスコア
カテゴリーRiverpodBloc
パフォーマンス
8/10
8/10
学習のしやすさ
8/10
6/10
エコシステム
7/10
9/10
コミュニティ
7/10
9/10
求人市場
7/10
7/10
将来性
8/10
7/10

長所と短所

Riverpod

長所

  • コード生成は完全に任意――従来の構文でも記述できる
  • Provider/Refという単一の概念に基づくため学習コストが低い
  • ProviderContainer.test()により追加パッケージなしで独立したユニットテストが可能
  • BuildContextに依存せずにproviderを読み取れる
  • DevTools拡張機能がriverpodパッケージに同梱されている(extension/devtools、v1.0.0)
  • Riverpod 3.0で実験的なmutations機能とriverpod_sqfliteによるオフライン永続化が追加
  • pub.devで月間2,970,654ダウンロードと高い利用実績
  • 2026-09-03にリリースされた3.4.3で示される非常に活発な開発ペース

短所

  • 従来の構文とコード生成構文のどちらを選ぶかはチーム自身が判断する必要がある
  • GitHubスター数(7,375)はBlocに劣る――より新しいコミュニティ
  • pub.devのpub point(140/160)はBlocの満点に及ばない
  • アーキテクチャの規約を強制しない――大規模チームでの一貫性はチームの規律次第になる
  • コード生成を使う場合、build_runnerのビルドチェーンへの依存が生じる
  • コード生成なしのunified syntaxはまだRFC段階で、安定していない

最適な用途

1〜5人規模の小規模チーム、および高速なMVP/スタートアップの反復開発既にFreezedやjson_serializableを使用しているプロジェクトオフラインファーストや実験的なstate mutationを必要とするアプリケーション少ないボイラープレートと単一の概念で素早く習得したいチーム活発で最新の依存関係チェーンを優先するプロジェクト

Bloc

長所

  • event/stateの分離が必須――任意の場所からstateを変更することはできない
  • BlocObserverによりすべてのstate遷移を一元的にログできる
  • 3層アーキテクチャ(Presentation/Business Logic/Data)が公式に文書化されている
  • pub.devで160/160の満点と公式の「Flutter Favorite」バッジを獲得
  • GitHubで12,482スターを獲得し、より大規模で定着したコミュニティを持つ
  • blocTestによりbuild/act/expectパターンで一貫性があり読みやすいテストを書ける
  • Bloc-to-Bloc Communicationにより多層・複数リポジトリの構成が公式にサポートされている
  • pub.devでwasm-readyおよびplatform:webタグを持ち、Webターゲットで成熟している

短所

  • 単純な画面であっても、個別のevent/stateクラスを書く必要がある
  • bloc_testパッケージと専用のテストDSL(blocTest)を学ぶ必要がある
  • flutter_blocの最新リリースは2025-05-02――16か月以上新しいリリースがない
  • build_runnerベースの公式コードジェネレーターは存在せず、ボイラープレート削減は公式のIntelliJ/VSCode拡張機能によるテンプレート生成に依存している
  • providerパッケージ(BlocProviderの基盤)への構造的な依存を取り除くことができない
  • Repository/DataProviderのコンストラクタ設定について、公式ドキュメントに明確な例が示されていない

最適な用途

10人以上の開発者が関わる、多モジュールのエンタープライズプロジェクト監査性・コンプライアンスが求められる規制業界(フィンテック、医療)ジュニアが多いチームで、強制力のあるアーキテクチャ規約を必要とするプロジェクトコードレビューでテストの一貫性を自動的に担保したいチーム長期的で成熟した、大規模なコミュニティに依拠したいプロジェクト

コード比較

Riverpod
// Riverpod - ユーザーリスト(コード生成あり)
// 出典: riverpod.dev 公式ドキュメントのパターン
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'user_list_provider.g.dart';

@riverpod
Future<List<User>> userList(Ref ref, {required int page}) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.fetchUsers(page: page);
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final usersAsync = ref.watch(userListProvider(page: 1));

    return usersAsync.when(
      data: (users) => ListView.builder(
        itemCount: users.length,
        itemBuilder: (context, index) => ListTile(
          title: Text(users[index].name),
          subtitle: Text(users[index].email),
        ),
      ),
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (error, stack) => Center(child: Text('Hata: $error')),
    );
  }
}

// コード生成なしの従来構文による代替案(公式ドキュメント、任意):
final userListClassicProvider =
    FutureProvider.autoDispose.family<List<User>, int>((ref, page) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.fetchUsers(page: page);
});
Bloc
// Bloc - ユーザーリスト(Event/State + Repository)
// 出典: bloclibrary.dev 公式Core Conceptsのパターン
import 'package:flutter_bloc/flutter_bloc.dart';

sealed class UserListEvent {}

class FetchUsers extends UserListEvent {
  FetchUsers({required this.page});
  final int page;
}

sealed class UserListState {}

class UserListInitial extends UserListState {}

class UserListLoading extends UserListState {}

class UserListLoaded extends UserListState {
  UserListLoaded({required this.users});
  final List<User> users;
}

class UserListError extends UserListState {
  UserListError({required this.message});
  final String message;
}

class UserListBloc extends Bloc<UserListEvent, UserListState> {
  UserListBloc({required this.repository}) : super(UserListInitial()) {
    on<FetchUsers>(_onFetchUsers);
  }

  final UserRepository repository;

  Future<void> _onFetchUsers(
    FetchUsers event,
    Emitter<UserListState> emit,
  ) async {
    emit(UserListLoading());
    try {
      final users = await repository.fetchUsers(page: event.page);
      emit(UserListLoaded(users: users));
    } catch (error) {
      emit(UserListError(message: error.toString()));
    }
  }
}

結論

「間違った選択」は存在しない――どちらも実績があり、MITライセンスだ。1〜5人の小規模チームで素早く反復開発するならRiverpod:ボイラープレートが少なく、コード生成は任意で、リリースペースも非常に活発(3.4.3、2026-09-03)。複数チームが関わり、監査可能なイベントフローが求められるエンタープライズプロジェクトならBloc:イベント/ステートの分離が必須で、BlocObserverもある。ただしflutter_blocの最新リリースは2025-05-02なので注視が必要だ。問うべきは「どちらが優れているか」ではなく、「規律をどこまで外部から強制すべきか」だ。

無料相談を受ける
FAQ

よくある質問

唯一絶対の正解はありません。1〜5人程度の小規模チームで素早く反復開発しており、アーキテクチャの判断をチーム内の会話だけで解決できるなら、Riverpod(ボイラープレートが少なく、コード生成は任意、BuildContextなしでテスト可能)がより適しています。複数チームが関わり、監査可能なイベントフローと厳格な規約が求められるエンタープライズプロジェクト(フィンテックや医療などの規制業界)では、Blocがイベント/ステートの分離とBlocObserverによる一元的なロギングを必須にすることで、より安全な基盤を提供します。

関連ブログ記事

すべての記事を見る
すべての比較