◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/開発ツール
⬡ 開発ツール/2026-05-30上級

OTAアップデートを段階配信する仕組みを、壊さずに育てる

EAS Updateで全ユーザーに即時配信するのは危険です。チャンネル設計・段階的ロールアウト・自動ロールバックまで、累計5,000万DLの運用で固まった配信アーキテクチャを実装コード付きで共有します。

EAS Update7OTA7段階的ロールアウトReact Native239Expo219ロールバック

✦ プレミアム記事

OTA(無線)アップデートで一番怖いのは、配信ボタンを押した瞬間に全ユーザーの端末が新バンドルを取りに行く、という挙動です。私が累計5,000万ダウンロードのアプリ群を運用していて、もっとも肝を冷やしたのも、まさにこの「即時・全量配信」で壊れたJavaScriptバンドルが数万台に同時に届いてしまった夜でした。アプリはストア審査を通さずに直せるのがOTAの利点ですが、裏を返せば、壊れたものも審査を通さずに一瞬で広がります。

EAS Update(Expoの無線更新基盤)はとても優秀ですが、デフォルトの使い方は「ブランチにpublishしたら、そのチャンネルを見ている端末が次回起動時に取得する」というシンプルなものです。これは小規模なうちは十分でも、ユーザー数が増えると「いきなり全員」がリスクそのものになります。即時全量配信を、5%→25%→100%の段階配信に作り替え、さらに壊れたバンドルを掴んだ端末を自動で前バージョンへ戻すところまでを、実際に運用しているコードと数値で共有します。

なぜ「チャンネル=環境」「ブランチ=中身」で分けるのか

EAS Updateには channel(チャンネル)と branch(ブランチ)という二つの概念があり、ここの設計を最初に間違えると後で必ず破綻します。私の整理はシンプルで、**channel はビルドに焼き込む「環境ラベル」、branch は実際に配信する「コードの中身」**です。ビルド(ネイティブバイナリ)は channel を見にいき、channel は任意の branch に向け替えられます。この間接参照こそが段階配信とロールバックの土台になります。

// eas.json — production を一段の channel ではなく、配信レーンとして設計する
{
  "cli": { "version": ">= 12.0.0" },
  "build": {
    "production": {
      "channel": "production",
      "autoIncrement": true
    },
    "production-canary": {
      "extends": "production",
      "channel": "production-canary"
    }
  },
  "submit": { "production": {} }
}

ポイントは、本番ビルドに production チャンネルを焼き込みつつ、配信時には production チャンネルを production-v1.4.0 のようなバージョン付きブランチに向けることです。こうしておくと、巻き戻したいときに「チャンネルの向き先を前のブランチに戻す」だけで全端末が次回起動時に旧バンドルへ戻ります。新しいバンドルを再publishして上書きするのではなく、向き先を変える——これが事故対応の速度を決めます。

段階配信の手順(そのまま回せるチェックリスト)

段階配信は、頭の中だけで運用すると必ずどこかで「今何%だったか」を見失います。私は次の手順をスクリプトとチェックリストに固定し、迷いをなくしました。

  1. 新バンドルを誰にも見せないバージョン付きブランチに publish する。
  2. production チャンネルを、そのブランチへ 5% だけ向ける。
  3. 配信から6時間、新旧のクラッシュ率差を最優先で監視する。
  4. 24時間経過時点で adoption 率を確認し、条件を満たせば 25% へ昇格する。
  5. 25% を 48時間維持して問題なければ 100% へ昇格する。
  6. 100% 到達後も 24時間は監視を緩めない。
#!/usr/bin/env bash
# scripts/staged-publish.sh — 段階配信を1コマンドに畳む
set -euo pipefail
 
BRANCH="production-$(date +%Y%m%d-%H%M)"
MESSAGE="${1:?commit message required}"
 
# 1. 新ブランチに publish(まだ誰にも見せない)
eas update --branch "$BRANCH" --message "$MESSAGE" --non-interactive
 
# 2. production チャンネルで 5% だけ新ブランチに向ける
eas channel:edit production \
  --branch "$BRANCH" \
  --rollout-percentage 5 \
  --non-interactive
 
echo "✅ $BRANCH を 5% に配信しました。"
echo "   24時間後に scripts/promote.sh $BRANCH 25 を実行してください。"
#!/usr/bin/env bash
# scripts/promote.sh — 様子を見て昇格する。引数で % を指定
set -euo pipefail
BRANCH="${1:?branch required}"
PCT="${2:?percentage required}"
 
eas channel:edit production \
  --branch "$BRANCH" \
  --rollout-percentage "$PCT" \
  --non-interactive
 
echo "✅ $BRANCH を ${PCT}% に昇格しました。"

私が昇格の前に必ず見る数字は二つです。ひとつはadoption率(その新バンドルを実際に取得・適用した端末の割合)。配信から24時間で、ロールアウト対象の70%以上が新バンドルを掴んでいなければ、配信経路かバンドルサイズに問題があると見ます。もうひとつは新旧のクラッシュ率の差で、新バンドル側のクラッシュ率が旧バンドルより20%以上悪化していたら昇格しません。5,000万DL規模だと5%でも数十万台あり、統計的に十分な母数が24時間で揃うため、この粒度で判断できます。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦eas.jsonとチャンネル/ブランチを分けた段階配信の最小構成(5%→25%→100%)を、そのまま使えるコードで示します
✦壊れたバンドルを掴んだ端末を自動で前バージョンへ戻す、起動時ヘルスチェック+ロールバックの実装手順
✦配信後24〜72時間のadoption率とクラッシュ率をどの閾値で監視し、いつ昇格・いつ巻き戻すかの具体的な判断基準
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ 開発ツール2026-08-09
Hermes バイトコードの差分更新を実測する — モジュール1本の追加が更新サイズを29倍にした
2.4MB の Hermes バイトコードで OTA 差分を実測しました。1行の変更は 2,104 バイト、モジュールを1本足すと 61,197 バイト。よく言われるモジュールID安定化はほぼ効かず、効いたのは別の2つでした。
⬡ 開発ツール2026-09-10
画面を暗くする機能を足したら、アプリを閉じたあとも iPhone が暗いままでした
expo-brightness の setBrightnessAsync は、Android では現在のアクティビティにだけ効き、iOS では端末の明るさそのものを変えます。戻す責任が片側にしかない理由と、AppState で後始末をするフックの実装をまとめました。
⬡ 開発ツール2026-09-04
EAS の secret は「アプリに入れない」設定ではありません — 接頭辞と可視性を別々に決める
EXPO_PUBLIC_ の接頭辞は成果物に入るかを決め、EAS の可視性は誰が読めるかを決めます。二つを重ねたときに OTA 更新でだけ値が消える筋道と、出荷前に自分の手で確かめる手順をまとめました。