Claude CodeでStrapi v5にアップグレード — id・attributesをgrepで洗う
Strapi v4からv5へは、upgrade toolとコードモッドで本体側を上げ、フロントのattributesとidをClaude Codeに洗い出させます。互換ヘッダーを使った段階移行の手順です。
Strapi v4からv5へのアップグレードは、upgrade toolで本体側の依存関係とコードを上げ、残った作業をClaude Codeに洗い出させる順で進めると手戻りが少なくなります。ツールが書き換えるのはStrapiプロジェクトの内側だけです。REST APIやGraphQLを呼ぶフロントエンドの data.attributes や数値の id は、ツールが触れない領域として残ります。この記事では、その残りを grep とClaude Codeで一覧にし、互換ヘッダーを使って1クライアントずつ切り替える手順をまとめます。
Strapi v4は2026年4月30日にサポートが終了し、4.26.2(2026年6月9日)が最後のv4リリースです。以降のv4更新はありません。
作業は「本体」と「呼び出し側」の2段に分かれる
ステップバイステップガイドは4つの段に分かれています。準備、自動移行、手動で直す破壊的変更、そしてAPIを呼ぶ側の移行です。前半2つはStrapiプロジェクトの中で完結します。後半の「呼び出し側」は、別リポジトリのNext.jsやモバイルアプリであることも多く、upgrade toolの対象外です。
v4からv5への進め方
- 1
準備: バックアップと最新v4への更新
データベースとコードを退避し、専用ブランチを切ります。v4が最新のminor・patchでなければ、先に
npx @strapi/upgrade minorで追いつかせます。 - 2
自動移行: upgrade toolを実行
npx @strapi/upgrade majorが依存関係を更新し、コードモッドを走らせます。 - 3
手動対応: __TODO__と破壊的変更
コードモッドが残した
__TODO__と、データベース・設定まわりの破壊的変更を確認します。 - 4
呼び出し側: 互換ヘッダーで段階移行
フロントやSDKの
attributesとidを、documentIdを使うフラット形式へ1つずつ移します。
Claude Codeの出番は主に3段目と4段目です。1段目と2段目は、人間がコマンドを打って結果を読むほうが安全です。
実行前の準備 — 最新のv4へ上げ、バックアップを取る
major の実行は、アプリがv4系の最新minorとpatchに達していないと止まります。ツールの説明にある例では、v4.14.4からv5.0.0へは2段階になります。まず最新のv4に上げます。
git switch -c chore/strapi-v5
npx @strapi/upgrade minor --dry
npx @strapi/upgrade minor--dry(-n)はファイルを書き換えずに、コードモッドの実行結果だけを確かめるオプションです。package.json も変更されず、依存関係の再インストールもされません。
バックアップは、SQLiteの標準構成なら .tmp/data.db を退避します。PostgreSQLやMySQLは、各データベースの手順でダンプを取ります。v5の起動時にはデータ移行スクリプトが走り、Strapiはこれを元に戻しません。v4へ戻す場合は、取っておいたバックアップとGitのタグから復元することになります。
プラグインがv5に対応しているかは、Marketplaceの各プラグインのページで事前に確認します。
upgrade toolを実行し、変更を読む
実行は1コマンドです。先に --dry で試し、問題なければ本番のブランチで実行します。
npx @strapi/upgrade major --dry
npx @strapi/upgrade major
git diff --statmajor は依存関係の更新とインストールに続けて、コードモッドを実行します。ガイドに載るコードモッドは12個です。
| コードモッド | 内容 |
|---|---|
| comment-out-lifecycle-files | 内容lifecycleファイルをコメントアウト(Document Service Middlewaresへ移行するため) |
| entity-service-document-service | 内容Entity ServiceからDocument Service APIへの移行を一部担当 |
| deprecate-helper-plugin | 内容@strapi/helper-plugin からの移行を一部担当 |
| sqlite3-to-better-sqlite3 | 内容SQLiteの依存を better-sqlite3 へ |
| s3-keys-wrapped-in-credentials | 内容aws-s3 プロバイダーの accessKeyId と secretAccessKey を credentials で包む |
| use-uid-for-config-namespace | 内容設定の get/set/has をドット形式からuid形式へ |
| strapi-public-interface / utils-public-interface | 内容importを新しい公開インターフェースへ |
| dependency-* 系(4つ) | 内容i18nプラグインの削除、react・react-dom・react-router-dom・styled-componentsの更新 |
特定のコードモッドだけ流し直したいときは、codemods ls で一覧を出し、codemods run で選びます。このコマンドは依存関係を更新せず、コードモッドだけを実行します。
ツールがやらないことも明記されています。ファイルの追加・削除・移動はしません。データの移行も担当外で、こちらはStrapi本体の起動時のデータベース移行が担います。実行後は、変更内容を確認してからアプリを起動するよう強く勧められています。
取りこぼしをClaude Codeに洗い出させる
entity-service-document-service は一部しか変換しません。documentId は元のコードからは推測できないので、コードモッドは __TODO__ を挿入して人間に返します。この __TODO__ が、次の作業の入口になります。
バックエンド側の __TODO__ を一覧にする
Claude Codeには、書き換えの前に「一覧を作る」ことだけを頼みます。一覧があれば、1件ずつ直すときの範囲が決まります。
upgrade tool実行後のこのブランチで、__TODO__ を含む箇所を
ファイル別に一覧にして。直さずに、各箇所が
(1) id から documentId への置き換え
(2) Entity Service から Document Service への書き換え
(3) その他
のどれかを分類して。分類を作らせる理由は、id を documentId に置き換えるだけでは直らない箇所が混ざるからです。documentId は新しい識別子で、ルートとリレーションに影響します。旧ID前提のURLや外部システムの保存値は、その場の判断が要ります。
フロント側の attributes と id を洗い出す
呼び出し側のリポジトリでは、まず機械的に探します。Claude Codeに探させる前に、grep の結果を見せておくと、読む対象が絞れます。
grep -rnE "\.attributes\b|attributes\." src | wc -l
grep -rnE "data\.(data|attributes)" src --include="*.ts" --include="*.tsx"
grep -rnE "\bid\b" src/lib/strapi src/api --include="*.ts"数値の id を使っている箇所は、\bid\b では他の用途も拾います。Strapiへのリクエストやレスポンスを扱うモジュールに範囲を絞るのが現実的です。結果が数百件になるなら、ファイルごとに分けて渡します。
件数が把握できたら、Claude Codeに分類を頼みます。
src 配下で Strapi REST API のレスポンスを読んでいる箇所を洗い出して。
次の3種に分け、ファイル名:行番号 で表にして。直さないこと。
A: data.attributes を経由してフィールドを読む
B: 数値の id を URL・キー・比較に使う
C: populate したリレーション(relation.data.attributes など)を辿るこの3分類は、レスポンス形式の変更に対応しています。v4では data.attributes の中にフィールドが入り、リレーションも data で包まれていました。v5はこれらを外し、documentId を識別子にします。Aは attributes の除去、Bは documentId への移行、Cは両方が重なる箇所です。
互換ヘッダーで1クライアントずつ切り替える
呼び出し側を一斉に書き換える必要はありません。REST APIには Strapi-Response-Format: v4 というリクエストヘッダーがあり、付けるとv4形式のレスポンス(data.attributes.*)が返ります。移行中は、これを全クライアントに付けておきます。
curl -H 'Authorization: Bearer <token>' \
-H 'Strapi-Response-Format: v4' \
'https://api.example.com/api/articles?populate=category'fetchなら headers に、Axiosなら axios.create の headers に同じキーを足します。ヘッダーの付与は、HTTPクライアントを1か所に集約していれば、その1か所の変更で済みます。
注意が必要なのは、このヘッダーが documentId の導入までは戻さない点です。ヘッダーを付けた状態でも、レスポンスには id(互換用)と documentId の両方が入ります。ヘッダーを外すと、REST APIが返す識別子は documentId だけになります。数値 id に依存する下流システムは、ヘッダーを外す前に直しておく必要があります。
GraphQLは別の仕組みで、プラグイン設定の v4CompatibilityMode を true にします。GraphQLは数値の id を返さないので、documentId へのクエリ変更は互換モードの前から必要です。
切り替えの順番
移行の手順は次の流れです。
- ヘッダーを付ける前に、代表的なレスポンス(populateしたリレーション、コンポーネント、メディアを含む)を保存する
- 各クライアントで
data.attributesの参照を外し、フラット形式に切り替える。数値のみだったidはdocumentIdを使う - テストが通ったクライアントから、ヘッダーを外す
- すべてのクライアントが移行できたら、ヘッダーをどこにも残さない(GraphQLは互換モードを
falseに戻す)
1の保存が、Claude Codeを使うときに効きます。移行前後のJSONを2つ並べ、差分を読み比べさせると、リレーションの取りこぼしを拾えます。
非対話実行で、繰り返し部分を自動化する
クライアントが複数リポジトリに分かれているなら、claude -p で同じ調査を回せます。-p(--print)を付けると、対話せずに結果を標準出力に返します。成功すると終了コードは0、失敗すると0以外です。
claude -p "src 配下で data.attributes を参照する箇所を、ファイル名:行番号で一覧にして。ファイルは変更しない。" \
--allowedTools "Read,Grep,Glob" > attributes-usage.txt--allowedTools に調べるだけのツールを並べておけば、許可を求められずに読み取りだけで動きます。書き換えまで任せるなら、Edit を足すか --permission-mode acceptEdits を選びます。Claude Codeのドキュメントでは、claude -p の実行は、権限モードが指定されなければManualモードで始まり、承認が要る呼び出しは拒否されます(v2.1.302以降)。
まず調査だけの -p を各リポジトリで回して一覧を集め、書き換えは対話セッションで1件ずつ見ながら進めると、レビューしやすい差分になります。
CLAUDE.mdに残しておく規約
移行の途中で作業を中断しても、次のセッションが同じ判断をできるように、規約をCLAUDE.mdに書いておきます。
## Strapi v5 移行の規約
- 新規コードで data.attributes を読まない。v5のフラット形式を使う
- エンティティの識別子は documentId。数値 id を URL やキャッシュキーに使わない
- Strapi-Response-Format: v4 ヘッダーは lib/strapi/client.ts の1か所だけで付ける
- ヘッダーを外すのは、対象クライアントのテストが通ってからヘッダーを付ける場所を1か所に決めておくと、「どのクライアントがまだv4形式に頼っているか」が git grep で確認できます。
破壊的変更はコードモッドの外にも残る
手動対応の項目には次があります。
- MySQL 5系は非対応。MySQLを使うなら
mysql2のみ - SQLiteは
better-sqlite3のみ - lifecycle hooksの発火のしかたが変わった
- 一部の環境変数はサーバー設定で扱われる
- カスタム設定は特定の要件を満たす必要がある
helper-pluginが削除された(管理画面の拡張に影響)watch-adminモードが既定で有効になった
データベースの項目は、コードを読むだけでは見落とします。使っているデータベースと設定の組み合わせを、Claude Codeに「この項目に該当するか」と聞くより、Strapiの破壊的変更データベースを開き、該当ページを1つずつ確認するほうが確実です。該当したページの内容だけを、Claude Codeに渡して修正案を出させると、範囲が小さく収まります。
v4へ戻せないことを前提に進める
Strapiには、v5からv4へ戻す自動の仕組みがありません。戻すなら、アップグレード前に取ったデータベースのバックアップを復元し、v4に対応するGitのブランチまたはタグをチェックアウトして、依存関係を入れ直します。そのため、本番に適用する前に、ステージング環境でデータ移行まで通すのが前提です。
Strapi Cloudを使っている場合は、バックアップとローカルのコード更新を済ませてから、Cloud CLIで yarn deploy または npm run deploy を実行します。デプロイ時にデータ移行スクリプトが自動で走ります。
コンテンツタイプのスキーマ定義まわりは、Claude CodeでStrapiのコンテンツタイプを定義する手順が詳しいです。同じくメジャーアップグレードの型でも、フレームワークごとに「ツールが書き換える範囲」が違います。Claude CodeでReact 19をアップグレードする手順は、公式codemodの範囲を表で仕分ける進め方の別例です。Railsのアップグレードも、ツールが出した差分を人間が読む流れは共通しています。
まとめ
Strapi v5への移行は、upgrade toolがStrapiプロジェクトの内側を、人間とClaude Codeが外側を担当する分担になります。ツールは documentId を推測できないので __TODO__ を残し、フロントの attributes と数値 id には手を付けません。Claude Codeに頼むのは「直す」より先に「一覧にする」ことで、互換ヘッダーを集約した1か所から外していけば、クライアントごとに安全に切り替えられます。バックアップとステージングでの通し確認だけは、人間が先に済ませておく作業です。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。