y-brew
TechBeansBrews

y-brew

HomeTechBeansBrews

© 2026 y-brew

記事一覧に戻る

Tech Article

•公開 2026年3月15日•

更新 2026年3月15日

microCMS で Content as Code

Lee Robinson の問題提起を手がかりに、microCMS CLI と GitHub Actions を使って microCMS でも Content as Code 的な運用がどこまで現実的かを検証した記事です。管理画面の強みを残しつつ Git を入口にするアプローチと、実際に詰まった点を整理しています。

Prerequisites

  • - headless CMS の基本的な運用イメージ
  • - Git / PR ベースの開発フローへの理解
  • - AI エージェントや CLI を使った作業に関心があると読みやすい

Key Points

  • - Lee Robinson の問題提起を5つに整理し、そのうち自分が強く反応した論点を切り出したこと
  • - microCMS を消さずに、Git / CLI を入口として追加するアプローチを試したこと
  • - GitHub Actions で Git から microCMS へ同期する最小フローを検証したこと
  • - managed state や stale_remote など、実運用で見えた詰まりどころを整理したこと

はじめに

前提として、microCMS にはコンテンツ編集履歴管理やレビュー、画面プレビューといった運用機能があります。実際、複数人での運用を支える機能はかなり揃っていて、管理画面中心でも十分に回せる場面は多いと思います。

その一方で、ローカルファイルや Git を中心にした開発フローと比べると、変更差分をコードレビューの流れにそのまま載せたり、AI エージェントにファイルを直接触らせたりする体験は別物です。そう考えると、管理画面の強みとは別に、Git や CLI を入口にしたときの強みもありそうだと感じていました。

きっかけは、Lee Robinson さんの Coding Agents & Complexity Budgets という記事でした。この記事では、Cursor のサイト運用で headless CMS を挟んだことで、以前のようにローカルファイルや Markdown をエージェントに直接触らせにくくなった、という問題意識が書かれていました。

自分は microCMS を使っており、microCMS CLI も個人開発していたので、この問題を microCMS の文脈でも試せるのではないかと思いました。そこで今回は、microCMS をやめるのではなく、microCMS のコンテンツを Git と CLI でも扱えるようにすると何が起きるか検証してみました。

Lee さんの記事で、何が問題だとされていたのか

元記事を読み直してみると、Lee さんが問題にしていたのは単に「diff が見づらい」だけではありませんでした。Cursor のサイト運用では、headless CMS を挟むことで次のような複雑さが増えていたと整理できます。

  1. ユーザー管理が CMS と GitHub で分かれてしまう
  2. プレビューのために draft mode や Vercel 側の権限管理が必要になる
  3. i18n 対応で CMS 用の連携や公開までの流れが複雑になる
  4. アセット配信や CDN コストが膨らむ
  5. コンテンツがネットワーク越しの抽象化に包まれ、AI やエージェントが grep や編集をしづらくなる

そのうえで Lee さんは、CMS を丸ごと消してコードと Markdown に戻す、という解決策を選んでいました。たとえば、エンジニアだけでコンテンツを触れるチームだとかなり成立しやすい面もあると思いました。

一方で、自分が強く気になったのは 5 つ目でした。コンテンツがローカルファイルとして存在すると、AI やエージェントが扱いやすい。Git diff / PR review / rollback も、そのままコンテンツ変更に使える。管理画面中心の運用は人間には便利でも、エージェントにとっては少し遠い操作になりやすい。

特に 2 つ目の「プレビューの複雑さ」は、静的に速く配信したいサイトほど気になる論点でした。CMS の下書きを確認しようとすると、preview 用の URL や認証、誰にその URL を見せるかといった運用上の部品が増えやすい。一方で、コンテンツ変更が Git の PR に載る形なら、PR に紐づいた preview deploy の URL をそのまま共有しやすく、少なくとも Lee さんはそこに大きなシンプルさを見ていたのだと思います。

ただ、microCMS の利用文脈では、非エンジニアの編集者が管理画面を使い続けたい場面も多いはずです。そこで自分は、CMS を消すのではなく、CMS を残したまま Git という入口を足すアプローチを試すことにしました。

今回試したアプローチ

今回の検証では、自作している mcms-cli の managed-json フローを使いました。これは、microCMS のコンテンツ本体をローカルの JSON として pull しつつ、どの remote 状態を基準に編集しているかを manifest で持つためのフォーマットです。verify や sync-status を挟みながら push できるので、「いま見ている JSON が本当に最新前提か」を確認しながら運用できます。

最小フローは次の形です。

microcms content pull tech_articles --all --out microcms-content --format managed-json --json
microcms content verify --dir microcms-content --endpoints tech_articles --id <contentId> --json
microcms content sync-status --dir microcms-content --endpoints tech_articles --id <contentId> --json
microcms content push --dir microcms-content --endpoints tech_articles --id <contentId> --execute --json

このプロジェクトでは、さらに GitHub Actions で main merge 後の Git -> microCMS 同期も試しました。

やっていること自体はシンプルで、main に入った managed JSON の差分だけを GitHub Actions が拾い、verify と sync-status を確認したうえで push --execute する流れです。実際の検証でも、1 文字だけ直した PR を merge すると、その 1 件だけが同期対象になりました。つまり、PR で見た差分が review で終わるのではなく、そのまま microCMS 反映まで運ばれる状態を作っていました。

実際の workflow は、やっていることだけ見ると次のような最小構成です。

- name: Detect sync scope from Git diff
  run: node scripts/content-as-code/detect-managed-content-scope.js ...

- name: Verify and push managed content
  run: node scripts/content-as-code/sync-managed-content-scope.js ...

前者の detect-managed-content-scope.js は Git diff を読んで、どの endpoint / record を同期するかを scope に落とすためのスクリプトです。後者の sync-managed-content-scope.js は、その scope を受けて mcms-cli の verify、sync-status、push --execute を順に実行し、どこかで失敗したら Actions も失敗として返す役割を持っています。

実際にやってみて良かったこと

まず分かりやすかったのは、コンテンツ変更が JSON diff として見えることでした。管理画面で直接編集する場合は「どこをどう変えたか」が追いにくいですが、Git 管理にすると PR 上で差分をレビューできます。

GitHub PR 上で content diff を確認している画面

GitHub の PR 上で、JSON の変更をそのままレビューできた場面です。

もうひとつ良かったのは、AI エージェントがローカルファイルとして扱えることです。今回の検証でも、実際に microcms-content/tech_articles/records/*.json を編集し、verify を通して、PR を作り、merge 後に microCMS へ反映するところまで回せました。

加えて、変更内容が PR に載る形だと、PR に紐づく preview deploy の URL を共有しやすいのも良さそうでした。CMS の下書きプレビューを見せるために専用の認証や URL の扱いを考えるのに比べると、少なくとも Git ベースの変更フローに乗っている分、共有のしかたはかなり素直に感じました。

この感触としては、「コンテンツをコードに変換した」というより、「コンテンツ変更をソフトウェア開発の流れに近づけた」という方が近い気がしました。

やってみて詰まったところ

一方で、単に Git に載せれば終わりという感じでもありませんでした。実際に詰まったのは次のような点です。

  • 単一選択のフィールドは、microCMS API 側では配列に近い形で返ってくる一方で、CLI 側では 1 つの値として扱いたくなる場面もあり、取得時と更新時でデータの形が揺れて見えることがあった
  • 記事本文の JSON だけでなく、_manifest.json のような「いまどの remote 状態を基準にしているか」を持つ管理用の情報も重要だった
  • remote の方が先に進むと、stale_remote(ローカルの前提が古い状態)として止まる

特に印象的だったのは、record だけを見ていると問題がなさそうでも、manifest が古いと sync が止まる点でした。ここは「Git で管理できるようになった」ことの裏側で、同期状態そのものが運用対象になる、という話だと思いました。

microCMS API 上では変更前の prerequisites が返っている画面

反映前の API レスポンスでは、まだ Headless CMS のままでした。

microCMS API 上で変更後の prerequisites が返っている画面

merge 後の同期が完了すると、API レスポンスでも ヘッドレス CMS へ変わっていることが確認できました。

自分の検証では、これは見えにくい不具合というより、安全装置として自然な失敗でした。古い前提のまま remote を上書きしないために止まっているので、むしろ止まってくれた方がよい場面でした。

ここまで試して見えたこと

ここまでの感触では、microCMS でも Git を入口にすることは十分できそうでした。検証前は、CMS と Code はどちらかを選ぶ話になりやすいのかなと思っていたのですが、実際には管理画面と Git / CLI の両方を入口として持つ方が自然に見えました。

一方で、管理画面の便利さを保ったまま Git を足すなら、責務が消えるわけではありません。管理用の同期情報、競合、同期状態の確認のような新しい関心事は増えます。このあたりは「CMS をなくした」ではなく、「運用の責務が別の形で見えるようになった」と捉える方が近そうです。

逆方向同期はどう考えているか

今回は Git -> microCMS までは回しましたが、microCMS -> Git の逆方向同期はまだ実装していません。

現時点では、最初の運用としては編集前に content pull するだけでも十分回ると感じています。一方で、将来的には webhook や PR 作成を含めた逆方向同期が欲しくなるかもしれません。この点は、今回の検証で見えた次の課題として整理しておきたいです。

向いていそうなケース / 向かないかもしれないケース

向いていそうだと感じたのは、PR review をコンテンツにも持ち込みたい場合、AI がローカルでコンテンツを触れる状態を作りたい場合、GitHub Actions まで含めて運用したい場合です。

逆に、管理画面だけで十分なケースや、_manifest.json や sync-status のような、同期状態を管理する仕組みをあまり運用したくないケースでは、そこまでメリットが大きくないかもしれません。

いまの時点でのまとめ

Lee Robinson さんの問題提起は、自分にとっては microCMS でもかなり自分ごとでした。実際に試してみると、Git diff や AI の扱いやすさはかなり魅力的に見えました。

一方で、managed state や逆方向同期など、運用として残る課題もはっきり見えました。

Reading Data

読了目安
約8分
セクション
9件
最終レビュー
2026年3月15日
Evergreen
Yes

Article Intent

Case Study

目次

  • はじめに
  • Lee さんの記事で、何が問題だとされていたのか
  • 今回試したアプローチ
  • 実際にやってみて良かったこと
  • やってみて詰まったところ
  • ここまで試して見えたこと
  • 逆方向同期はどう考えているか
  • 向いていそうなケース / 向かないかもしれないケース
  • いまの時点でのまとめ