Claude CodeでStrapiのコンテンツタイプを定義する手順と落とし穴
Strapi 5のschema.jsonをClaude Codeに編集させる手順を、再起動とビルドの扱い、フィールド名変更でデータが消える落とし穴、CLAUDE.mdの規約例までを解説します。
Claude CodeでStrapiのコンテンツタイプを扱う全体像
Strapiのコンテンツタイプは、管理画面のContent-type Builderで作る方法と、プロジェクト内のschema.jsonを直接書く方法の2通りで定義できます。Claude Codeに任せるのは後者です。管理画面の操作はClaude Codeからは行えませんが、schema.jsonならファイルとして編集でき、差分もGitで追えます。
ただし、schema.jsonの編集は見た目より危険です。フィールド名を1つ変えただけで、既存データが空になる場合があります。Claude Codeに書かせる前に、守らせたいルールを決めておくのが先です。
先に押さえる3点
- Content-type Builderは開発環境(Development)専用で、本番ではスキーマを変えられない
schema.jsonのキーを直接書き換えると、データが引き継がれないおそれがある。改名はstrapi rename:field(5.57.0以降)かContent-type Builderの確認を通す- 変更後の型定義は
strapi ts:generate-typesで作り直す
作業は5段で進む
各段の詳細は後の節で扱います。ここでは、段ごとに何を見れば次へ進めるかだけ並べます。
Claude Codeでコンテンツタイプを足す順序
- 1
雛形を作る
src/api/<名前>/content-types/<名前>/schema.jsonができていることを確かめます。 - 2
属性を書かせる
Gitの差分で、変わったのが
attributesの追加行だけかを見ます。 - 3
起動して反映を確かめる
strapi developのログにエラーがなく、再起動が流れたかを見ます。 - 4
型を作り直す
型定義ファイルに新しい属性が入り、フロントエンドのビルドが通るかを見ます。
- 5
改名はコマンドで
./database/migrationsに、新しいマイグレーションファイルが1つ増えたかを見ます。
schema.jsonはどこにあり、何が書かれているか
コンテンツタイプのモデルは./src/api/[api-name]/content-types/[content-type-name]/に置かれ、中核がschema.jsonです。コンポーネントは./src/componentsの下に、カテゴリ名のサブフォルダごとに置きます。Content-type Builderで作った場合も、strapi generateで作った場合も、schema.jsonは自動で生成されます。
schema.jsonは、次の4つの塊でできています。
- 設定:
kind(collectionTypeかsingleType)と、保存先のcollectionName - 情報:
infoのdisplayName・singularName・pluralNameなど - 属性:
attributesにフィールドの型と制約を並べる - オプション:
optionsのdraftAndPublishなど
singularNameとpluralNameはAPIのルートやテーブル名の元になり、どちらもkebab-caseで書きます。strapi generateでは、単数形と複数形を同じ名前にできません。
公式のモデル解説に沿った形で、レストランの定義を書くと次のようになります。
{
"kind": "collectionType",
"collectionName": "restaurants",
"info": {
"displayName": "Restaurant",
"singularName": "restaurant",
"pluralName": "restaurants",
"description": ""
},
"options": { "draftAndPublish": true },
"attributes": {
"title": { "type": "string", "minLength": 3, "maxLength": 99, "unique": true },
"description": { "type": "text", "required": true },
"slug": { "type": "uid", "targetField": "title" }
}
}属性のtypeには、string・text・richtext・uid・integer・datetime・boolean・jsonのほか、media・relation・component・dynamiczoneなどがあります。required・unique・minLengthなどの検証キーは、属性の中に並べます。private: trueにすると、その属性はサーバーの応答から外れます。
雛形はstrapi generateに作らせ、属性をClaude Codeに書かせる
ファイルを手で一から作ると、フォルダ構成やkindを取り違えがちです。雛形はstrapi generateのcontent-typeに作らせ、そこへ属性を足す分担が安全です。
npm run strapi generate
# 「content-type」を選び、kebab-caseの単数形・複数形を指定するgenerateは、コントローラーやサービス、データベースのマイグレーションファイルも作れます。コンテンツタイプだけを作るなら、content-typeを選ぶ流れです。インタラクティブCLIで作ったコンテンツタイプは、draftAndPublishの既定がfalseになります。モデル側の既定はtrueなので、下書きと公開を使うなら、生成後にoptionsを見直します。
雛形ができたら、Claude Codeには次のように頼みます。
src/api/restaurant/content-types/restaurant/schema.json に
属性を足してください。
- address: 必須の短い文字列
- openedAt: 日付時刻
- menus: Menu と多対多
変更前に、既存フィールドの名前を変えていないか差分で報告してください。最後の一文が効きます。フィールド名の変更はデータ消失に直結するため、変更の有無を毎回報告させます。
CLAUDE.mdに書いておく規約の例
毎回の依頼文に書き足すより、CLAUDE.mdに固定したほうが抜けません。Strapi向けの断片は、次のようになります。
## Strapi のスキーマ規約
- コンテンツタイプは src/api/*/content-types/*/schema.json を編集する。dist/ は触らない
- 既存フィールド名・singularName・pluralName・collectionName は変更しない
- フィールド名を変えたいときは編集せず、`npm run strapi rename:field <uid> <旧> <新>` を提案する
- 属性を足したら `npm run strapi ts:generate-types` を実行する
- スキーマ変更後は `npm run develop` で起動し、エラーが出ないことを確認する「dist/は触らない」は、Strapiのビルド成果物が次のビルドで置き換わるためです。公式も、フォルダ整理用のgroups.jsonについて「ソース側を編集し、distの方は編集しない」と述べています。
再起動とビルド — いつ反映されるか
schema.jsonを編集したあとの反映は、起動方法で変わります。
strapi developはファイルウォッチャーを持ち、必要なときにアプリケーションを再起動します。開発中はこちらで回すのが前提です。strapi startにはウォッチャーがないため、本番相当の起動でschema.jsonを書き換えても、再起動するまで反映されない構成だと考えておくのが安全です。ビルド済みの成果物を読む設定ファイルでは、公式が「再ビルドと再起動で反映される」と明記しています。
strapi developの説明には「必要なとき」としか書かれておらず、schema.jsonの変更がどの条件で再起動を起こすかまでは載っていません。Claude Codeにスキーマを書かせた直後は、ログに再起動が流れたかを見て、流れていなければ手で起動し直してください。
Content-type Builderが開発環境専用である点も、運用に効きます。本番でスキーマを編集する想定はなく、変更はコードとして開発環境で作り、デプロイで本番に届けます。schema.jsonをClaude Codeに書かせる流れは、この前提と相性が良い構成です。
フォルダ整理のgroups.jsonもClaude Codeに任せられる
Content-type Builderの左のナビに出るフォルダは、src/content-structure/groups.jsonに保存されます。ファイルはコードと一緒にバージョン管理され、デプロイで環境間を移ります。
- フォルダの階層は3段まで。1つのコンテンツタイプが属せるフォルダは1つ
- 同じ親の下で、フォルダ名は大文字小文字を区別せずに重複できない
- 手書きでおかしな参照があると、起動時に修復または無視され、
[content-structure]で始まるログが出る - データ転送(Data Transfer)はこのファイルを運ばない
起動時は寛容に修復されますが、Content-type Builderからの保存は厳格で、規則に反する構造は拒否されます。コンポーネントはこのファイルに含まれず、フォルダ分けもできません。
フィールド名の変更でデータが消える — マイグレーションの落とし穴
最大の落とし穴はここです。公式のContent-type Builderの説明には、次の挙動が明記されています。
落とし穴
schema.jsonのキー名を直接変えると、既存データが失われうる
5.57.0以降のContent-type Builderでは、フィールドを改名して保存するときに確認ダイアログが出ます。確認すると、列を作り直さずカラム名を変えるので、既存データが残ります。5.57.0より前は、この引き継ぎがありませんでした。型・リレーション・コンポーネントを同時に変えたときは、保存されず空のフィールドが作られます。
Claude Codeがschema.jsonのキーを直接書き換えると、この確認を経ずに旧来の扱いになり得ます。ここで使うのがstrapi rename:fieldです。
npm run strapi rename:field api::article.article title headingこのコマンドは、./database/migrationsにマイグレーションファイルを作り、そのパスを表示します。中身は、カラム(またはテーブル)を作り直さずに名前を変える処理で、次回のアプリケーション起動時に1回だけ実行されます。コマンドラインは確認を取れないため、ポリモーフィックリレーションのように移行できない改名は、スキーマを変えずに拒否されます。
そのほかの落とし穴を、表にまとめます。
| 操作 | 起きること |
|---|---|
| フィールド名を変える(5.57.0より前) | 起きること既存データが引き継がれない |
| 名前変更と同時に型・リレーション・コンポーネントを変える | 起きることデータは保存されず、空で作り直される |
| コンテンツタイプやコンポーネントのAPI IDを変える | 起きること新しいテーブルが作られ、旧テーブルのデータは管理画面から見えなくなる |
| コンポーネントを削除する | 起きること使われている全コンテンツタイプ・エントリから消える |
| コンテンツタイプを削除する | 起きること管理画面のエントリは消えるが、データベースのデータは残る |
3行目のAPI ID変更は、rename:fieldの対象外です。singularNameやcollectionNameをClaude Codeに整えさせないよう、先ほどのCLAUDE.mdで禁じているのはこのためです。
リレーションとi18nをschema.jsonで書くときの注意
リレーションは、type: "relation"にrelationとtargetを指定して書きます。relationにはoneToOne・oneToMany・manyToOne・manyToManyなどがあります。双方向にするときは、所有する側がinversedBy、逆の側がmappedByを持ちます。たとえば植物と持ち主なら、植物側にmanyToOneとinversedBy: "plants"、持ち主側にoneToManyとmappedBy: "owner"を書きます。
Claude Codeにリレーションを書かせたら、片方の定義だけで終わっていないかを見ます。相手側のファイルにもmappedByまたはinversedByが入ったかを、差分で確かめてください。targetはAPI形式のUID(api::plant.plantのような形)で指定します。
多言語化は、属性ごとにpluginOptionsのi18nでlocalized: trueを指定します。コンテンツタイプ側のoptionsで下書き公開を切り替える点と合わせ、Content-type Builderのチェックボックスに対応するキーが、schema.jsonでは別々の場所にあります。
型定義の再生成を自動化する
TypeScriptのプロジェクトでは、属性を足すたびにstrapi ts:generate-typesでスキーマの型を作り直します。Claude Codeのhooksに載せれば、schema.jsonの編集後に自動で走ります。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | grep -q 'schema.json$' && npm run strapi ts:generate-types || true"
}
]
}
]
}
}hooksの書き方そのものは、Packerのhook設定の記事にも別の例があります。ts:generate-typesの出力先を--out-dirで変えるのは、型を別のディレクトリに作って既存の型と比べたいときくらいで、通常は使いません。公式も、型が機能するにはデフォルトのtypesディレクトリが必要だと注意しています。
Strapi AIとClaude Codeはどう違うか
Strapi自身にも、自然言語でコンテンツタイプを作るStrapi AIがあります。管理画面の右下から使うアシスタントで、Growthプランで利用でき、月1,000クレジットが含まれます。既存のStrapiやフロントエンドのコードを取り込んだり、Figmaや画像から構造を取り出したりもできます。
使い分けの軸は、変更をコードの差分として残したいかどうかです。Strapi AIは管理画面の操作で、Content-type Builderと同じく開発環境で保存します。Claude Codeはschema.jsonを直接編集するので、レビュー・テスト・マイグレーションファイルの追加までを、通常の開発フローに乗せられます。マイグレーションの安全な回し方は、Drizzle ORMのマイグレーション運用と同じ考え方で、生成物を人間が読んでから適用する形になります。
まとめ
Strapiのschema.jsonは、Claude Codeに向いた定義ファイルです。ただ、追加は任せやすい一方、改名・削除はデータを巻き込みます。追加は任せ、改名はrename:fieldに切り出し、削除は人間が決める。この線引きをCLAUDE.mdに書いておくのが、いちばん事故を減らします。