公開日 2026-06-11

Flutter + FVM で開発環境のバージョンを固定する

Windows 11 の Flutter 環境に FVM を追加し、プロジェクトごとに Flutter SDK を固定して `fvm flutter run` まで確認できるようにする。

目次

  1. 1. ゴールと非対象
  2. 対象読者
  3. この記事で到達する状態
  4. 非対象
  5. 2. 先に FVM が必要な理由を掴む
  6. 3. FVM を入れ、プロジェクトとエミュレーターを用意する
  7. 3-1. 前提の環境構築がまだなら先に済ませる
  8. 3-2. Windows で FVM を導入する
  9. 3-3. Flutter プロジェクトを作成する
  10. 3-4. エミュレーターを起動する
  11. 4. プロジェクトごとの Flutter バージョンを固定する
  12. 4-1. stable の最新を固定する
  13. 4-2. 何が作られたか確認する
  14. 5. lib/main.dart を書き換えて fvm flutter run で確認する
  15. 5-1. lib/main.dart を次の内容に書き換える
  16. コードのポイント
  17. 5-2. 固定した SDK で起動する
  18. 6. チームで共有するときの最小ルール
  19. 7. まとめ

Windows 11で始めるFlutter開発環境 の次に、案件ごとの差分をどう吸収するかをそろえておくと、後続の記事や実務作業へ入りやすくなります。この記事では FVM を導入し、Flutter SDK をプロジェクト単位で固定して、fvm flutter run でアプリを起動するところまでをまとめます。iOS、CI、monorepo は扱いません。

1. ゴールと非対象

対象読者

  • Windows 11 で Flutter の環境構築までは終わっている人
  • 複数案件や複数サンプルで Flutter SDK の版ずれを避けたい人
  • まずは VS Code + Android Emulator で FVM の最小運用を固めたい人

この記事で到達する状態

  • Windows で FVM を導入できる
  • プロジェクトごとに Flutter SDK のバージョンを固定できる
  • .fvmrc と VS Code 連携の役割を説明できる
  • fvm flutter run で固定した SDK からアプリを起動できる

非対象

  • Riverpod や REST API などのアプリ実装テーマ
  • CI での FVM キャッシュ最適化
  • Flutter fork や commit hash 指定の高度な運用
  • Android Studio の詳細設定

グローバル Flutter を消して FVM だけに寄せる話ではありません。最初の導入は Windows 11で始めるFlutter開発環境 で済みます。案件ごとの差分だけを FVM に持たせる構成です。

2. 先に FVM が必要な理由を掴む

グローバル Flutter だけで運用すると、どのプロジェクトも同じ SDK を見に行きます。1 本のサンプルだけなら困りませんが、案件 A は古めの stable、案件 B は新しい stable といった状態になると、どこかで版ずれが出ます。

flowchart LR
  G[グローバル Flutter] --> A[project-a]
  G --> B[project-b]
  A --> X[同じ SDK を参照]
  B --> X
  subgraph FVM運用
    A2[project-a + .fvmrc] --> A3[project-a 用 SDK]
    B2[project-b + .fvmrc] --> B3[project-b 用 SDK]
  end

FVM を入れる目的は、Flutter SDK をもう 1 回インストールし直すことではありません。プロジェクトごとに「このフォルダはこの Flutter を使う」という設定を持たせることにあります。

  • グローバル Flutter: flutter create や最初の導入確認に使う土台
  • FVM: プロジェクトごとの Flutter SDK を固定する仕組み
  • .fvmrc: どのバージョンを使うかを残す設定ファイル

ここを分けておくと、後続の Flutterで最初に詰まりやすいDartの書き方 や API 通信の記事を試すときも、「どの SDK で動かしているか」が曖昧になりません。

3. FVM を入れ、プロジェクトとエミュレーターを用意する

3-1. 前提の環境構築がまだなら先に済ませる

環境構築がまだの場合は Windows 11で始めるFlutter開発環境 を先に参照してください。

この記事は、すでに次の状態になっている前提で進めます。

  • flutter --version が通る
  • flutter doctor で Android 向けの最低限がそろっている
  • Android Emulator を起動できる

3-2. Windows で FVM を導入する

Flutter が入っていれば dart コマンドも使えるはずなので、PowerShell で次を実行します。

dart pub global activate fvm

続けて fvm コマンドが見えるか確認します。

fvm --version

fvm が見つからない場合は、PowerShell を閉じて開き直してから再実行してください。それでも通らない場合は、%LOCALAPPDATA%\Pub\Cache\bin が User PATH に入っているか確認します。

次のコマンドで LOCALAPPDATA の実際の値を確認します。

$env:LOCALAPPDATA

出力例:

C:\Users\<ユーザー名>\AppData\Local

この出力に \Pub\Cache\bin を足したパスが User PATH に含まれている必要があります。

C:\Users\<ユーザー名>\AppData\Local\Pub\Cache\bin

3-3. Flutter プロジェクトを作成する

FVM を導入したあと、サンプル用のプロジェクトを作成します。

flutter create my_fvm_app
cd my_fvm_app

ここではいったんグローバル Flutter でプロジェクトを作ります。固定対象はこの次の手順で設定します。

3-4. エミュレーターを起動する

利用可能なエミュレーターを確認します。

flutter emulators

表示された ID を指定して起動します。

flutter emulators --launch <emulator_id>

この時点ではまだ FVM 固定前です。先にエミュレーターだけ立ち上げておくと、後で fvm flutter run の確認がスムーズです。

4. プロジェクトごとの Flutter バージョンを固定する

4-1. stable の最新を固定する

プロジェクト直下で次を実行します。

fvm use stable --pin

このコマンドで行われることは 3 つです。

  • 指定した Flutter SDK をキャッシュへ取得する
  • プロジェクト直下に .fvmrc を作る
  • .fvm ディレクトリと VS Code 向け設定を更新する

参考(今は実行不要): チームで使う版がすでに決まっている場合は、stable --pin の代わりに具体版を指定できます。初めて試すときは上の stable --pin で進めてください。

fvm use 3.29.2

stable --pin は「いまの stable を 1 回固定する」コマンドです。毎回最新へ自動追従するわけではないため、あとで更新したいときは改めて fvm use stable --pin を実行します。

4-2. 何が作られたか確認する

固定後の見え方は次のようになります。

my_fvm_app/
├─ .fvm/
├─ .fvmrc
├─ .vscode/
├─ lib/
└─ pubspec.yaml

ここで最低限押さえたいのは次の 2 点です。

  • .fvmrc は「このプロジェクトが使う Flutter の版」を表す
  • VS Code では .vscode/settings.json が更新され、プロジェクトごとの Flutter SDK を参照しやすくなる

VS Code の統合ターミナルでは、FVM が設定した SDK を Dart Code 拡張が拾うため、flutter コマンドがプロジェクトの SDK を向くことがあります。最初は混乱しやすいので、この記事では明示的に fvm flutter ... を使います。

必要に応じて診断コマンドでも確認できます。

fvm doctor
fvm flutter --version
fvm doctor の出力(プロジェクト情報・固定バージョンの確認) fvm flutter --version の出力(Flutter 3.41.4 stable)

fvm doctor の VSCode 欄に No .vscode directory found と表示される場合は、VS Code でプロジェクトを一度開くと .vscode/settings.json が生成されます。

5. lib/main.dart を書き換えて fvm flutter run で確認する

5-1. lib/main.dart を次の内容に書き換える

lib/main.dart は次の内容で書き換えます。

このファイルは、FVM で固定した SDK を前提にアプリが起動する状態を確認するための最小画面です。.fvmrc、VS Code 連携、fvm flutter run という3つの確認点が UI 上にも見えるようにしています。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FVM Version Pinning Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
      ),
      home: const FvmPinnedHomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final ColorScheme colorScheme = Theme.of(context).colorScheme;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter + FVM'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: <Widget>[
          Card(
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: const <Widget>[
                  Text(
                    'このプロジェクトは FVM で SDK を固定しています。',
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                  ),
                  SizedBox(height: 8),
                  Text('グローバル Flutter ではなく、プロジェクトの設定を優先して実行する想定です。'),
                ],
              ),
            ),
          ),
          const SizedBox(height: 16),
          Text(
            '確認ポイント',
            style: TextStyle(
              fontSize: 16,
              fontWeight: FontWeight.bold,
              color: colorScheme.primary,
            ),
          ),
          const SizedBox(height: 8),
          const ChecklistTile(
            title: '`.fvmrc` がプロジェクト直下にある',
            description: 'どの Flutter 版を使うかを共有する設定です。',
          ),
          const ChecklistTile(
            title: '`fvm flutter run` でアプリが起動する',
            description: 'どの SDK を使っているかをコマンドで明示できます。',
          ),
          const ChecklistTile(
            title: 'VS Code で Flutter SDK の切り替えが追従する',
            description: '`.vscode/settings.json` の更新対象です。',
          ),
          const SizedBox(height: 16),
          Container(
            padding: const EdgeInsets.all(16),
            decoration: BoxDecoration(
              color: colorScheme.surfaceContainerHighest,
              borderRadius: BorderRadius.circular(16),
            ),
            child: const Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(
                  '次に覚えるコマンド',
                  style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                ),
                SizedBox(height: 8),
                Text('fvm flutter doctor'),
                Text('fvm flutter run'),
                Text('fvm use stable --pin'),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class ChecklistTile extends StatelessWidget {
  const ChecklistTile({
    super.key,
    required this.title,
    required this.description,
  });

  final String title;
  final String description;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        leading: const Icon(Icons.check_circle_outline),
        title: Text(title),
        subtitle: Text(description),
      ),
    );
  }
}

コードのポイント

① アプリの入り口で FVM 前提の確認画面へ集約している

    return MaterialApp(
      title: 'FVM Version Pinning Demo',
      home: const FvmPinnedHomePage(),
    );

home を専用の FvmPinnedHomePage に寄せることで、このサンプルが何を確認する画面かを明確にしています。SDK の切り替え確認が目的の記事なので、カウンターアプリを残すより、確認項目がそのまま見える画面にしたほうが意図が伝わります。

.fvmrcfvm flutter run を画面上のチェック項目にしている

          const ChecklistTile(
            title: '`.fvmrc` がプロジェクト直下にある',
            description: 'どの Flutter 版を使うかを共有する設定です。',
          ),
          const ChecklistTile(
            title: '`fvm flutter run` でアプリが起動する',
            description: 'どの SDK を使っているかをコマンドで明示できます。',
          ),

確認ポイントを本文だけでなく UI にも置いているため、起動後に「何が確認できれば成功か」を見失いにくくなります。.fvmrc と実行コマンドの両方を並べることで、設定ファイルと実行経路の役割差も読み取りやすくしています。

③ 補助 Widget に分けて同じ見た目を繰り返している

class ChecklistTile extends StatelessWidget {
  const ChecklistTile({
    super.key,
    required this.title,
    required this.description,
  });

同じカードを3回並べる箇所を ChecklistTile へ切り出すと、本文で説明したい論点が UI の構造に埋もれません。小さな部品に分けておくことで、あとから確認項目を増やす場合も本文との差分を最小限に保てます。

5-2. 固定した SDK で起動する

次のコマンドを実行します。

fvm flutter run

複数デバイスが見えている場合は、fvm flutter devices で ID を確認してから -d を付けて起動します。

fvm flutter devices
fvm flutter run -d <device_id>

確認したいのはアプリの見た目より、次の 3 点です。

  • fvm flutter run でビルドが最後まで通ること
  • エミュレーターにアプリが表示されること
  • 今後のコマンド実行も fvm flutter ... でそろえられること
Android Emulator で Flutter + FVM アプリが起動している画面

6. チームで共有するときの最小ルール

FVM を入れる目的は、ほかの開発者も同じ SDK で再現できる状態を共有することです。

  • 最低限共有するのは .fvmrc
  • ローカルの SDK 実体そのものを配布する必要はない
  • 版上げするときは fvm use stable --pinfvm use <version> をもう一度実行する

FVM は .gitignore の更新も補助できますが、共有するのは SDK 本体ではなく、どの SDK を使うかという設定ファイルです。

Android Studio を使う場合は、Flutter SDK の参照先をプロジェクト内の .fvm/flutter_sdk へ向け直す必要があります。VS Code より一段手数が増えるため、最初の 1 本としては VS Code のほうが進めやすいです。

7. まとめ

Flutter の最初の環境構築はグローバル Flutter で十分です。そのあとで案件ごとの差分を吸収したくなったら、FVM を足して .fvmrc でプロジェクト単位の版を固定します。この二層構成にしておくと、新しい記事を試すときも、チームで同じサンプルを動かすときも、参照中の SDK が曖昧なまま進まなくて済みます。

次は Flutterで画像・SVG・アイコンを管理する(flutter_gen最小構成) に進むと、FVM でそろえた環境の上でアセット参照の置き場所まで先に整えられます。そのあとで Dart の読み書きを整理したい場合は Flutterで最初に詰まりやすいDartの書き方 へ進むと流れがつながります。

シリーズ 2/14

このシリーズ

Flutter導入と基礎

  1. 1. Windows 11で始めるFlutter開発環境:Android Emulatorで動かすまで
  2. 2. Flutter + FVM で開発環境のバージョンを固定する 現在の記事
  3. 3. Flutterで画像・SVG・アイコンを管理する(flutter_gen最小構成)
  4. 4. Flutterで最初に詰まりやすいDartの書き方:final・const・null safety・async/await を最初に整理する
  5. 5. DartのStream入門(非同期データの流れをつかむ)
  6. 6. FlutterのWidgetライフサイクル入門(initState / dispose で詰まらないために)
  7. 7. FlutterでBuildContextとKeyを理解する
  8. 8. Flutterのレイアウト入門(Column / Row / Stack の使い分け)
  9. 9. Flutterのテーマ設計入門(ThemeData + Theme Extension)
  10. 10. FlutterでMediaQueryとLayoutBuilderを使って画面サイズに対応する(スマホ・タブレット両対応)
  11. 11. FlutterのContainerとSizedBoxを使いこなす(余白・サイズ・装飾の基本)
  12. 12. FlutterのListViewとGridViewで一覧画面を作る(基本パターン)
  13. 13. Flutterのダイアログ・スナックバー・ボトムシートを使う(確認・通知UIの基本)
  14. 14. FlutterのTabBarとBottomNavigationBarで複数画面を切り替える