2026年4月30日に、GitHub上の dotnet/docs 公式リポジトリで global.json に関するドキュメント更新がマージされました。結論から言うと、NuGetのロックファイルを使っている .NET プロジェクトでは、global.json の rollForward を disable にして、SDKバージョンも依存関係グラフも同じ状態に保つべきという点が明確化されています。更新自体は小さな文言追加ですが、CI/CD、GitHub Actions、Azure Pipelines、Dockerビルド、開発者PCのSDK管理に影響する可能性があります。(GitHub)
今回の公式ドキュメント更新で何が変わったか
今回の更新は、GitHub上の dotnet/docs リポジトリにある docs/core/tools/global-json.md に対する変更です。プルリクエスト #53348 は2026年4月30日にマージされ、対象コミットは 74e8a04 です。差分としては1ファイルのみで、rollForward の disable に関する説明へ脚注が追加されました。(GitHub)
変更前の disable は、主に「ロールフォワードせず、完全一致が必要」という説明でした。更新後はその説明に加えて、package lock filesを使う場合は rollForward を disable に設定し、SDKバージョンと依存関係グラフを同期させるというガイダンスが追加されています。Microsoft Learnの現行ページでも、disable は「正確なSDK一致を要求する」設定として説明され、ロックファイル利用時の推奨が脚注で示されています。(Microsoft Learn)
| 確認項目 | 更新前の読み取り方 | 更新後に強調された実務上の意味 |
|---|---|---|
rollForward: disable | 指定したSDKと完全一致させる設定 | ロックファイル運用では推奨設定として見る |
| package lock files | NuGet依存関係を固定する仕組み | SDK差分による依存関係グラフのズレも考慮する |
| CI/CD | SDKが近いバージョンなら問題ないと考えがち | ロックファイル利用時はSDKの完全一致を優先する |
| 影響範囲 | global.json の説明文レベル | GitHub Actions、Azure Pipelines、Docker、開発端末のSDK管理に関わる |
重要なのは、今回の更新が「新機能追加」ではなく「既存の推奨事項を見つけやすくしたドキュメント整理」である点です。ただし、実務ではこの種のドキュメント更新が、ビルド失敗やCI再現性の問題を避ける判断材料になります。
rollForward: disable とは何か
global.json は、.NET CLIが使用するSDKバージョンを指定するためのファイルです。リポジトリルートやソリューション配下に配置することで、dotnet build、dotnet restore、dotnet test などで使われるSDKを制御できます。
rollForward は、指定したSDKが見つからない場合や、より新しいSDKを許容する場合の選択ルールです。Microsoft Learnでは、rollForward の値として patch、feature、minor、major、latestPatch、latestFeature、latestMinor、latestMajor、disable などが説明されています。disable はその中でも最も厳しく、指定したSDKバージョンと完全一致しない場合はロールフォワードしません。(Microsoft Learn)
典型的な設定は次の形です。
{
"sdk": {
"version": "8.0.302",
"rollForward": "disable"
}
}
この例では、8.0.302 のSDKがインストールされている環境だけで、そのSDKを使って .NET CLI が実行されます。8.0.303 や 8.0.400 が入っていても、指定SDKがなければ自動的には使われません。
なぜロックファイル運用で disable が重要なのか
NuGetのロックファイル、つまり packages.lock.json は、復元されるパッケージ依存関係を固定するための仕組みです。NuGet公式ドキュメントでは、RestorePackagesWithLockFile を有効にすると packages.lock.json が生成され、CI/CDなどで依存関係をその場で変えたくない場合は --locked-mode や RestoreLockedMode=true を使う方法が説明されています。(Microsoft Learn)
しかし、ここで見落としやすいのが SDK自体も依存関係グラフに影響する場合がある という点です。
たとえば、開発者PCでは .NET SDK 8.0.407 でロックファイルを生成したのに、CI環境では global.json のロールフォワード設定によって 8.0.408 が使われるケースがあります。関連Issueでは、SDK差分により Microsoft.NET.ILLink.Tasks の参照バージョンが変わり、NU1004 エラーにつながった事例が報告されています。(GitHub)
つまり、ロックファイルでNuGetパッケージを固定していても、SDKが変われば次のようなズレが起きる可能性があります。
| 起きること | 具体的な影響 |
|---|---|
| SDKに同梱・暗黙参照されるパッケージが変わる | packages.lock.json と復元結果が一致しない |
| CIだけ新しいSDKにロールフォワードする | ローカルでは成功し、CIだけ失敗する |
| Visual Studioやビルドエージェントの更新でSDKが変わる | 何も変更していないPRでビルドが落ちる |
| DockerイメージやGitHub ActionsランナーのSDKが変わる | 再現性のあるビルドの前提が崩れる |
ロックファイルは「依存関係の再現性」を高める仕組みですが、SDK選択が揺れていると、その再現性に穴ができます。今回のドキュメント更新は、その穴を防ぐために global.json 側でもSDKを固定する必要があると明確にしたものです。
影響を受けやすいプロジェクト
今回の更新で特に確認すべきなのは、次のようなプロジェクトです。
| 対象 | 確認すべき理由 |
|---|---|
packages.lock.json をリポジトリにコミットしている .NET アプリ | SDK差分でロックファイルとの差異が出る可能性がある |
dotnet restore --locked-mode をCIで使っている | 依存関係グラフが変わるとCIが失敗する |
RestoreLockedMode=true を設定している | ロックファイルとの差分を許容しないため影響が出やすい |
GitHub Actionsで actions/setup-dotnet を使っている | global.json やランナー上のSDK選択を確認する必要がある |
Azure Pipelinesで UseDotNet@2 の useGlobalJson を使っている | パイプライン側のSDK解決と global.json の整合性確認が必要 |
Dockerfileで mcr.microsoft.com/dotnet/sdk イメージを使っている | ベースイメージ更新によりSDKが変わる可能性がある |
| Blazor、MAUI、WASM、トリミング関連を使うプロジェクト | SDK依存のタスクや暗黙的なパッケージの影響を受けやすい |
特に注意したいのは、rollForward を明示していない global.json です。Microsoft Learnでは、SDKバージョンが指定されていて rollForward がない場合、既定のポリシーとして patch が使われると説明されています。つまり「何も書いていないから完全固定」ではありません。(Microsoft Learn)
まず確認すべきファイルと設定
今回の更新を受けて、開発チームやクラウド管理者が最初に見るべき場所は次の4つです。
| 確認場所 | 見るポイント |
|---|---|
global.json | sdk.version が完全なバージョンか、rollForward が disable か |
packages.lock.json | ロックファイルを使っているか、複数プロジェクトで配置が分散していないか |
.csproj / Directory.Build.props | RestorePackagesWithLockFile や RestoreLockedMode の有無 |
| CI/CD定義 | dotnet restore --locked-mode、setup-dotnet、UseDotNet@2、Docker SDKイメージの指定 |
確認コマンドとしては、まず次を実行します。
dotnet --version
dotnet --list-sdks
リポジトリ内の global.json を探す場合は、Linux/macOSなら次のように確認できます。
find . -name global.json -o -name packages.lock.json
Windows PowerShellでは次のように確認できます。
Get-ChildItem -Recurse -Filter global.json
Get-ChildItem -Recurse -Filter packages.lock.json
複数の global.json がある場合は、どのディレクトリから dotnet コマンドを実行するかで参照されるファイルが変わる可能性があります。Microsoft Learnでは、.NET SDK muxerは現在の作業ディレクトリから上位階層を検索し、MSBuild SDK resolverはソリューションやプロジェクトの場所を基準に検索すると説明されています。(Microsoft Learn)
推奨される global.json の設定例
ロックファイルを使うアプリケーションでは、基本的に次のようにSDKを完全固定します。
{
"sdk": {
"version": "8.0.302",
"rollForward": "disable"
}
}
version は自社プロジェクトで実際に採用するSDKバージョンに置き換えてください。8.0.302 は形式を示す例であり、すべてのプロジェクトに推奨される固定値ではありません。
allowPrerelease も必要に応じて明示します。プレビューSDKを使わない通常の本番プロジェクトでは、次のようにしておくと意図が明確になります。
{
"sdk": {
"version": "8.0.302",
"rollForward": "disable",
"allowPrerelease": false
}
}
ただし、.NET 10以降の新機能検証やプレビューSDK評価を行う検証ブランチでは、allowPrerelease を別途検討します。本番ビルドと検証ビルドで同じ global.json を使うと、意図せずプレビューSDKが混ざるリスクがあります。
GitHub Actionsで確認すべきポイント
GitHub Actionsを使っている場合は、actions/setup-dotnet の設定を確認します。公式READMEでは、global-json-file 入力を使って global.json からSDKバージョンを読み取れること、dotnet-version と global-json-file の両方を指定した場合は両方のバージョンがインストールされることが説明されています。(GitHub)
ロックファイル運用では、次のように global.json を明示的に参照し、restoreはlocked modeで実行します。
steps:
- uses: actions/checkout@v6
- name: Setup .NET SDK
uses: actions/setup-dotnet@v5
with:
global-json-file: ./global.json
- name: Restore
run: dotnet restore --locked-mode
- name: Build
run: dotnet build --no-restore
注意点は、dotnet-version: 8.0.x のような幅のある指定と、global.json による固定を混在させないことです。幅のある指定は便利ですが、ロックファイルで再現性を優先するビルドでは、意図せず新しいSDKが入る原因になります。
GitHub Actionsのキャッシュも確認が必要です。setup-dotnet にはNuGetパッケージキャッシュ機能があり、ロックファイルをキャッシュキーに使う説明があります。キャッシュはビルド高速化には有効ですが、SDKの不一致を解決するものではありません。(GitHub)
Azure Pipelinesや自己ホストランナーでの注意点
Azure Pipelinesでは、UseDotNet@2 がSDKを取得してPATHに追加します。Microsoft Learnでは、useGlobalJson を使うと global.json からSDKをインストールでき、workingDirectory で検索ルートを指定できると説明されています。(Microsoft Learn)
例は次の通りです。
- task: UseDotNet@2
inputs:
packageType: 'sdk'
useGlobalJson: true
workingDirectory: '$(Build.SourcesDirectory)'
- script: dotnet restore --locked-mode
displayName: Restore locked dependencies
- script: dotnet build --no-restore
displayName: Build
自己ホストランナーや社内ビルドエージェントでは、過去に入れたSDKが残っていることがあります。rollForward が disable でなければ、インストール済みSDKの状態によってビルド結果が変わる可能性があります。クラウド管理者は、エージェントに入っているSDK一覧を定期的に棚卸しし、ジョブ開始時に dotnet --version をログへ出す運用にすると原因調査が早くなります。
- script: |
dotnet --version
dotnet --list-sdks
displayName: Show .NET SDK versions
Dockerビルドで見落としやすいポイント
Dockerを使う場合、global.json とDockerイメージのSDKバージョンをそろえる必要があります。
悪い例は、SDKイメージを広いタグで指定し、リポジトリ側ではロックファイルを使っているケースです。
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet restore --locked-mode
RUN dotnet build --no-restore -c Release
この場合、8.0 タグが将来どのSDKを含むかは更新タイミングに左右されます。ロックファイルの再現性を重視するなら、プロジェクトで採用するSDKバージョンとベースイメージをできるだけ具体的に合わせます。
FROM mcr.microsoft.com/dotnet/sdk:8.0.302 AS build
WORKDIR /src
COPY . .
RUN dotnet --version
RUN dotnet restore --locked-mode
RUN dotnet build --no-restore -c Release
実際に利用可能なタグやパッチの扱いは時期によって変わるため、Dockerfile更新時には公式イメージのタグとプロジェクトの global.json をセットで確認してください。
移行準備の進め方
すでに latestPatch や latestFeature を使っているチームが、いきなり disable に変えると、開発者PCやCIでSDK不足が起きることがあります。移行は次の順序で進めると安全です。
| 手順 | 作業内容 | 失敗しやすいポイント |
|---|---|---|
| 1 | 現在CIで使われているSDKを dotnet --version で確認する | ローカルのSDKだけ見て判断する |
| 2 | packages.lock.json と RestoreLockedMode の有無を確認する | ロックファイルが一部プロジェクトにだけある |
| 3 | 採用するSDKバージョンを1つ決める | Visual Studio付属SDKとCI SDKがずれる |
| 4 | global.json に rollForward: disable を追加する | version が古く、誰もそのSDKを持っていない |
| 5 | GitHub ActionsやAzure Pipelinesで同じSDKをインストールする | dotnet-version: 8.0.x のような指定を残す |
| 6 | dotnet restore --locked-mode を実行して確認する | ロックファイル更新が必要な変更と混同する |
| 7 | SDK更新ルールをチームで決める | 各自が任意のタイミングでSDKを更新する |
移行時にCIが失敗した場合、まず見るべきなのは NU1004 のようなロックファイル関連エラー、dotnet --version の出力、packages.lock.json の差分です。SDKを上げる必要がある場合は、SDK更新とロックファイル再生成を同じPRにまとめるとレビューしやすくなります。
latestPatch や latestFeature を使ってはいけないのか
必ずしもそうではありません。
latestPatch や latestFeature は、SDKのセキュリティ更新や修正を取り込みやすくするためには便利です。Microsoft Learnでも、latestFeature や latestPatch は指定範囲内のより新しいSDKを使う設定として説明されています。(Microsoft Learn)
ただし、ロックファイルを使って「毎回同じ依存関係でビルドする」ことを重視しているプロジェクトでは、SDK側だけ自動的に変わると整合性が崩れます。
判断基準は次のように考えると分かりやすいです。
| 運用方針 | 向いている設定 |
|---|---|
| アプリ本番ビルドで再現性を最優先する | rollForward: disable |
ロックファイルを使い、CIで --locked-mode を使う | rollForward: disable |
| OSSライブラリで複数SDKに対する互換性を検証する | マトリックスビルドで複数SDKを明示 |
| SDK修正を早めに取り込みたい検証環境 | latestPatch や latestFeature を検討 |
| 開発者の利便性を優先する小規模プロジェクト | チーム内合意があれば緩いロールフォワードも可 |
大切なのは、rollForward の値を「なんとなく」選ばないことです。ロックファイルを使うなら、SDKもロック対象の一部として扱うのが今回の更新の実務的な読み方です。
よくある失敗と対策
rollForward を省略して完全固定したつもりになる
global.json にSDKバージョンだけを書くと、完全固定に見えます。
{
"sdk": {
"version": "8.0.302"
}
}
しかし、SDKバージョンが指定されていて rollForward がない場合、既定では patch ポリシーが使われます。指定SDKがない環境では、より新しいパッチへ進む可能性があります。ロックファイル運用では、意図を明確にするために disable を書くのが安全です。(Microsoft Learn)
CIだけ成功し、ローカルだけ失敗する
CIに正しいSDKが入っていても、開発者PCに同じSDKがないとローカル復元やビルドが失敗します。対策として、READMEやオンボーディング手順に次の情報を明記します。
dotnet --version
dotnet --list-sdks
必要なSDKがなければ、公式の .NET ダウンロードページや社内配布手順からインストールします。Visual Studioユーザーの場合、Visual Studio更新でSDKが変わることもあるため、スタンドアロンSDKの導入要否も検討します。Microsoft Learnでも、Visual Studioのアップグレードで以前のSDKが削除される場合があることに触れています。(Microsoft Learn)
SDK更新とロックファイル更新を別々に行う
SDKだけを上げるPRと、packages.lock.json を更新するPRを分けると、どちらの変更がビルド差分の原因か分かりにくくなります。
実務では、次のように1つの変更単位にまとめるのが分かりやすいです。
- global.json の SDK version を更新
- 必要に応じて Dockerfile / CI 定義のSDK指定を更新
- dotnet restore --force-evaluate などでロックファイルを再生成
- dotnet restore --locked-mode で再確認
- dotnet build / dotnet test を実行
SDK更新は「開発ツールの更新」ではなく「依存関係グラフに影響し得る変更」として扱うと、レビュー品質が上がります。
技術意思決定者が見るべき運用ルール
開発チームが大きくなるほど、global.json とロックファイルの扱いは個人判断に任せない方が安全です。特に、クラウド管理者、ソリューションアーキテクト、テクニカルリードは次のルールを整備しておくとよいでしょう。
| ルール | 目的 |
|---|---|
本番ビルドでは global.json を必須にする | SDK選択を暗黙にしない |
ロックファイル利用時は rollForward: disable を標準にする | SDKと依存関係グラフを同期させる |
CIログに dotnet --version を必ず出す | 障害調査を早くする |
| SDK更新PRは月次またはスプリント単位でまとめる | 開発者ごとの更新タイミング差をなくす |
| Dockerfile、GitHub Actions、Azure PipelinesのSDK指定を棚卸しする | 実行環境ごとのズレをなくす |
| ロックファイルの差分はレビュー対象にする | 意図しない依存関係変更を検出する |
このルールは、セキュリティ更新を止めるためのものではありません。むしろ、SDK更新を計画的に行い、ロックファイル差分とビルド結果を確認したうえで安全に取り込むためのルールです。
今すぐ取るべきアクション
今回のGitHub上の公式ドキュメント更新で確認すべき点は、シンプルです。packages.lock.json を使っているなら、global.json の rollForward を確認し、必要なら disable に変更することです。
最初に次の順で確認してください。
dotnet --version
dotnet --list-sdks
find . -name global.json -o -name packages.lock.json
次に、global.json を次の観点で見直します。
{
"sdk": {
"version": "使用するSDKの完全なバージョン",
"rollForward": "disable"
}
}
最後に、CIで次を実行して、ロックファイルとSDK選択が一致しているか確認します。
dotnet restore --locked-mode
dotnet build --no-restore
dotnet test --no-build
今回の更新は、見た目には小さなドキュメント差分です。しかし、ロックファイルを使う .NET プロジェクトでは、SDKバージョンの揺れがCI失敗や再現性低下につながります。GitHub Actions、Azure Pipelines、Docker、開発者PCのSDKを一つの運用ルールとして見直し、global.json と packages.lock.json をセットで管理することが、次に取るべき具体的な対応です。

コメント