Keystatic (GitHub storage) 導入・運用ガイド

このドキュメントは、Next.js プロジェクトにおける Keystatic の GitHub Storage モードを使用した導入、設定、および運用に関する標準ガイドラインです。

1. 導入目的と全体像

目的: Headless CMS を別途契約することなく、管理画面からコンテンツを更新し、すべての変更を GitHub 上のコミットとして保存・管理する(Git-based CMS)。

アーキテクチャ概要

2. 基本セットアップ

以下のパッケージとディレクトリ構成を基本とします。

依存パッケージ

npm install @keystatic/core @keystatic/next

必須ファイル構成 (App Router)

パス 役割
keystatic.config.ts Keystatic の設定ファイル(スキーマ定義、保存先設定)
app/keystatic/[[...params]]/page.tsx 管理画面のUIコンポーネントを描画するルート
app/api/keystatic/[[...params]]/route.ts GitHub認証およびAPI処理を行うルート

3. GitHub storage の設定

keystatic.config.ts にて、ストレージモードを GitHub に設定します。

重要: リポジトリ名の指定 設定ファイルはクライアントサイド(ブラウザ)でも実行されるため、リポジトリ名などの識別子には必ず NEXT_PUBLIC_ プレフィックスが付いた環境変数を使用してください。
// keystatic.config.ts
import { config, fields, collection } from '@keystatic/core';

export default config({
  storage: {
    kind: 'github',
    // クライアント側でも参照できるよう NEXT_PUBLIC_ をつける
    repo: process.env.NEXT_PUBLIC_KEYSTATIC_GITHUB_REPO as `${string}/${string}`,
  },
  // ... collections settings
});

4. GitHub App の作成と設定

Keystatic がリポジトリを操作するために、GitHub App を作成してインストールする必要があります。

認証フロー

  1. ユーザーが /keystatic にアクセス
  2. GitHub へリダイレクトされ認証
  3. GitHub が /api/keystatic/github/oauth/callback へコード付きで戻す

GitHub App 設定のポイント

注意: 作成後、対象のリポジトリに対してこの App を「Install」しないとアクセスできません。

5. 環境変数(一般形)

.env.local および本番環境(Vercel 等)に以下の変数を設定します。

変数名 公開範囲 説明
NEXT_PUBLIC_KEYSTATIC_GITHUB_REPO 公開 owner/repo-name 形式。設定ファイルで参照。
NEXT_PUBLIC_KEYSTATIC_GITHUB_APP_SLUG 公開 GitHub App のスラッグ(ID名)。
KEYSTATIC_GITHUB_CLIENT_ID 非公開 GitHub App の Client ID。サーバー側のみで使用。
KEYSTATIC_GITHUB_CLIENT_SECRET 非公開 GitHub App の Client Secret。絶対に公開しないこと。
KEYSTATIC_SECRET 非公開 セッション暗号化用。ランダムな32文字以上の文字列。

6. コンテンツ読み込み

フロントエンド(/news 等)で Keystatic 管理データを表示する場合、サーバーコンポーネントで読み込むのが基本です。

// app/news/page.tsx
import { createReader } from '@keystatic/core/reader';
import keystaticConfig from '@/keystatic.config';

const reader = createReader(process.cwd(), keystaticConfig);

export default async function NewsPage() {
  // スラグ一覧を取得
  const slugs = await reader.collections.news.list();
  
  // 各記事の詳細を取得
  const newsList = await Promise.all(
    slugs.map(slug => reader.collections.news.read(slug))
  );

  return (
    // ...レンダリング処理
  );
}

7. 本番で記事が反映されない時の対策

Vercel などでのデプロイ時、ソースコードとして import されていない content/ ディレクトリ内のファイルは、ビルドのトレース対象外となり、本番環境に含まれないことがあります。

対策: outputFileTracingIncludes

next.config.mjs にて、コンテンツディレクトリを明示的に含める設定を行います。

// next.config.mjs
const nextConfig = {
  experimental: {
    // どのルートでデータが必要か指定(ここでは全ルート対象の例、または /news など特定も可)
    outputFileTracingIncludes: {
      '/**': ['./content/**/*'], 
    },
  },
};

export default nextConfig;

8. UI/レイアウト上の注意

Keystatic の管理画面(/keystatic)は、サイト共通のヘッダーやフッター、グローバル CSS の影響を受けるとレイアウト崩れや動作不良を起こす可能性があります。

9. よくあるエラーと原因

redirect_uri is not associated with this application

原因: GitHub App の設定画面で、「Callback URL」にアクセス中の URL(例: 本番ドメイン)が含まれていません。
対策: GitHub App の設定を修正し、本番URLを追加してください。

Repo not found / 404 Error

原因:

  1. 環境変数の repo 値が間違っている。
  2. GitHub App が作成されたが、対象のリポジトリに「Install」されていない。

ビルド時の型エラー

原因: keystatic.config.ts 内で process.env... をそのまま渡すと string | undefined になるため。
対策: as `${string}/${string}` のようにキャストするか、変数の存在チェックを行ってください。

10. 運用フロー(推奨)

  1. 記事作成: 管理画面 (/keystatic) で記事を書き、保存・公開する。
  2. 自動コミット: Keystatic が裏側で GitHub にコミット&プッシュを行う。
  3. CI/CD 起動: GitHub へのプッシュを検知して Vercel 等がビルドを開始。
  4. 本番反映: 数分後に本番サイトが更新される。

※ 反映されない場合は、ビルドログを確認し、セクション 7 の「トレース設定」を見直してください。

補足: Git-backed CMS の運用イメージ

つまり「差分をGitに積んでデプロイへ流す」運用が基本で、これが便利さの本体です。

なお local storage は開発専用なので、本番で編集したい場合は GitHub storage(または Cloud)が前提になります。

✅ 導入完了チェックリスト

本番デプロイ前に確認してください。