ビルドが失敗した日、まず疑うのは自分が触った場所です。私も長らくそうしていました。
けれど何本かアプリを並べて運用していると、どこも触っていないのに結果だけが変わる、という日がやってきます。コミットは同じ。依存も同じ。違っていたのは、ビルドが走った向こう側の Mac でした。
EAS Build のログをいちばん上まで戻すと、Spin up build environment という地味なセクションがあります。ここに、そのビルドが実際に使ったイメージ名が出ています。私はある時期まで、この行を一度も読んだことがありませんでした。
書かなかったときの既定値は latest ではありません
まず、ここを取り違えたままの方が多い印象があります。
eas.json に image を書かなかった場合、EAS Build はそのビルドを auto エイリアスで走らせます。latest ではありません。auto は、プロジェクトの設定・Expo SDK のバージョン・React Native のバージョンを見て、そのプロジェクトに適したイメージを選びます。
つまり既定の挙動は「常に最新」ではなく、「あなたの SDK に合わせて選ばれる」です。おだやかに聞こえますが、裏を返すと SDK を上げた瞬間に選ばれるイメージが変わる ということでもあります。
指定できる値は、フルネームか、エイリアス(auto / latest / sdk-57 のような SDK 別)のどちらかです。性質はそれぞれ違います。
| 指定 | いつ中身が動くか | 向いている場面 |
|---|---|---|
フルネーム(例: macos-tahoe-26.5-xcode-26.6) | ほぼ動かない(軽微な更新のみ) | 環境を固定したいとき |
auto(既定) | SDK・RN のバージョンを上げたとき | Expo の推奨に素直に乗るとき |
sdk-57 などの SDK 別 | 新しい SDK がリリースされるたび | SDK 単位で足並みを揃えたいとき |
latest | 新しいイメージが出るたび | 常に最新の Xcode で試したいとき |
latest は「安定版」の意味ではなく「いちばん新しいものが割り当てられる別名」です。ここを安定寄りの言葉として読んでしまうと、判断が逆向きになります。
SDK エイリアスが1つ動くと、何が一緒に入れ替わるのか
抽象論だと実感が湧かないので、Expo が公開しているビルドサーバーのイメージ一覧から、SDK 56 と SDK 57 の iOS イメージを並べてみます。
| 項目 | sdk-56(macos-tahoe-26.4-xcode-26.4) | sdk-57(macos-tahoe-26.5-xcode-26.6・latest) |
|---|---|---|
| Xcode | 26.4(17E202) | 26.6(17F113) |
| macOS | Tahoe 26.4.1 | Tahoe 26.5.2 |
| Node.js | 22.22.2 | 22.23.1 |
| pnpm | 10.33.3 | 11.9.0 |
| fastlane | 2.233.1 | 2.236.1 |
| Maestro | 2.5.1 | 2.6.1 |
目が留まるのは pnpm です。10.33.3 から 11.9.0 へ、メジャーバージョンをまたいでいます。SDK のエイリアスを1つ上げただけで、パッケージマネージャが世代ごと入れ替わる。Android 側も同様で、ubuntu-26.04-jdk-17-ndk-r27b(sdk-56)から ubuntu-26.04-jdk-17-ndk-r27b-sdk-57 へ動くと、pnpm は同じく 10.33.3 から 11.9.0、node-gyp は 12.3.0 から 13.0.0 に上がります。
ネイティブモジュールを含むプロジェクトで node-gyp のメジャーが動くのは、静かですが小さくない変化です。「Expo SDK を上げた」という1行の作業報告の下に、これだけの入れ替えが同時に入っています。
数字は執筆時点で Expo のビルドサーバー情報ページに掲載されているものです。イメージは随時追加されるので、判断の前にご自身で当該ページを開いて確認してください。
自分のビルドがどのイメージで通ったのかを拾う
固定するかどうかを決める前に、まず現在地を知る必要があります。順番はこうしています。
- EAS のダッシュボードで、直近の成功したビルドを開く
- ログの
Spin up build environmentセクションまでスクロールする - そこに出ているイメージ名をそのまま控える
auto で走らせている場合、ここに出る名前が「いま自分のアプリが実際に通っている環境」です。eas.json を見ても書いていないので、ログを開かないと分かりません。
控えた名前は、そのまま eas.json に書けます。
{
"build": {
"production": {
"ios": {
"image": "macos-tahoe-26.5-xcode-26.6"
},
"android": {
"image": "ubuntu-26.04-jdk-17-ndk-r27b-sdk-57"
}
}
}
}プロファイルごとに分けることもできます。私は本番だけ固定し、検証用のプロファイルは新しい環境を早めに踏むために動かしたままにする、という組み方を好みます。壊れてもよい場所を1つ持っておくと、本番を固定していても取り残されずに済むからです。
{
"build": {
"preview": {
"distribution": "internal",
"ios": { "image": "latest" }
},
"production": {
"ios": { "image": "macos-tahoe-26.5-xcode-26.6" }
}
}
}固定する場合と、固定しないほうがよい場合
固定は万能ではありません。両方に副作用があります。
固定して得られるのは再現性です。同じコミットを来月ビルドしても、同じ Xcode・同じ fastlane で通ります。審査に出す直前にビルドが落ちて原因が分からない、という時間の使い方を減らせます。
一方で、固定したまま放置すると別の期限に当たります。Expo が支えると表明しているのは、App Store Connect に提出できる安定版の Xcode、実際には最新版とその1つ前まで、という範囲です。Apple が最低 Xcode バージョンの要件を引き上げれば、固定したイメージはいずれ提出に使えなくなります。固定は「決めなくていい」ではなく「決める時期を自分で選べる」という意味だと捉えています。
ですから、固定するなら固定した日付と理由をコメント代わりにコミットメッセージへ残しておくと、半年後の自分が助かります。私はここを何度か手抜きして、なぜこのイメージ名なのか思い出せずに調べ直しました。
なお、更新のたびに何が実際に入っているかを確かめる話は、手元の expo が実際どのバージョンなのかを数えるでも別の角度から扱っています。
Xcode 27 が来る前に、1つだけ決めておく
iOS 27 の正式リリースは9月14日と報じられています。新しい Xcode が続けば、latest の指す先も、SDK 別エイリアスの中身も、いずれ入れ替わります。
今日のうちにやることは1つで十分です。直近の成功ビルドのログを開き、Spin up build environment に出ているイメージ名を控えてください。控えるだけで構いません。固定するかどうかは、その名前を見てから決められます。
実機側の確認をこれから始める方は、正式版が来る前に予備の iPhone で公開中のアプリを触るの手順と合わせて進めると、順番が組み立てやすくなります。Android 側の期限を並行して抱えている場合は、targetSdkVersion の実効値を確かめるも同じ週に置いておくと安全です。
ここまでお読みいただきありがとうございました。ビルド環境は、動いているうちは誰も見ない場所です。落ち着いている今のうちに一度だけ開いておくと、慌ただしい週の自分が少し楽になります。