AI

ヘッドレスCMS比較:Strapi vs Payload vs Directus 2026年版でコンテンツ管理を構築する

オープンソースラボ編集部2026年6月14日

ヘッドレスCMS比較:Strapi vs Payload vs Directus 2026年版でコンテンツ管理を構築する

Next.js・Nuxt・Remixなどのフロントエンドフレームワークと組み合わせてコンテンツ管理を行うヘッドレスCMSが標準的な選択肢となっています。Strapi(Node.js製・最大シェア)・Payload(Next.js統合・TypeScript First)・Directus(SQL直接管理・多機能)の3つが2026年のOSSヘッドレスCMSデファクトスタンダードです。

ヘッドレスCMSを選ぶ理由

  • フロントエンド分離: Next.jsやMobileアプリなど複数フロントエンドから同一コンテンツAPIを共有
  • 開発者体験: コンテンツタイプを定義するだけで管理UIとREST/GraphQL APIが自動生成
  • コスト削減: Contentful($300+/月)→セルフホストで$20/月のVPS費用のみ
  • 拡張性: プラグイン・フック・カスタムAPIで完全なビジネスロジックカスタマイズが可能

主要CMSの概要

Strapi

2015年公開、TypeScript製のOSSです。GitHubスター64k+。OSSヘッドレスCMSの最大シェアを持つNode.js製プラットフォームで、Content Type Builder(GUIでスキーマ定義)・REST API・GraphQL・Role & Permissions・Upload Plugin(メディア管理)が標準装備されています。

# Strapi v5 セットアップ
npx create-strapi-app@latest my-cms   --dbclient=postgres   --dbhost=localhost   --dbport=5432   --dbname=strapi   --dbusername=strapi   --dbpassword=password

cd my-cms
npm run develop
// src/api/article/controllers/article.ts: カスタムコントローラー
import { factories } from '@strapi/strapi'

export default factories.createCoreController('api::article.article', ({ strapi }) => ({
  // デフォルトのfindをオーバーライドしてカスタムロジックを追加
  async find(ctx) {
    const { query } = ctx

    // 公開記事のみを返す(is_published = true)
    query.filters = {
      ...(query.filters || {}),
      is_published: true,
    }

    const { data, meta } = await super.find(ctx)

    // レスポンスを加工
    const enriched = data.map(article => ({
      ...article,
      reading_time: Math.ceil(article.attributes.content?.split(' ').length / 200),
    }))

    return { data: enriched, meta }
  },

  // SEO用のメタデータを付加するカスタムエンドポイント
  async findBySlug(ctx) {
    const { slug } = ctx.params
    const article = await strapi.entityService.findMany('api::article.article', {
      filters: { slug, is_published: true },
      populate: ['cover_image', 'author', 'categories', 'seo'],
    })
    if (!article?.length) return ctx.notFound('記事が見つかりません')
    return { data: article[0] }
  },
}))
// config/plugins.ts: Strapi プラグイン設定
export default () => ({
  upload: {
    config: {
      provider: 'aws-s3',
      providerOptions: {
        credentials: {
          accessKeyId: process.env.AWS_ACCESS_KEY_ID,
          secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        },
        region: process.env.AWS_REGION,
        params: { Bucket: process.env.AWS_BUCKET },
      },
    },
  },
  email: {
    config: {
      provider: 'sendgrid',
      providerOptions: { apiKey: process.env.SENDGRID_API_KEY },
      settings: { defaultFrom: 'noreply@example.com' },
    },
  },
  i18n: { enabled: true },
  graphql: { enabled: true, config: { endpoint: '/graphql', playgroundAlways: false } },
})

Payload CMS

2022年公開、TypeScript製のOSSです。GitHubスター33k+。Next.js App RouterにネイティブなTypeScript First CMSで、コレクション・グローバル・ブロックをTypeScriptコードで定義してスキーマの型安全を完全に保証します。データベースにMongoDBまたはPostgreSQLを選択できます。

// payload.config.ts: Payload CMSの完全な設定
import { buildConfig } from 'payload'
import { postgresAdapter } from '@payloadcms/db-postgres'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import { s3Storage } from '@payloadcms/storage-s3'
import { ja } from '@payloadcms/translations/languages/ja'

export default buildConfig({
  admin: {
    user: 'users',
    meta: { titleSuffix: '- My CMS', favicon: '/favicon.ico' },
  },
  i18n: { supportedLanguages: { ja } },
  editor: lexicalEditor(),
  db: postgresAdapter({
    pool: { connectionString: process.env.DATABASE_URL },
  }),
  plugins: [
    s3Storage({
      collections: { media: true },
      bucket: process.env.S3_BUCKET,
      config: {
        credentials: {
          accessKeyId: process.env.AWS_ACCESS_KEY_ID,
          secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        },
        region: process.env.AWS_REGION,
      },
    }),
  ],
  collections: [
    {
      slug: 'articles',
      admin: { defaultColumns: ['title', 'status', 'publishedAt'] },
      versions: { maxPerDoc: 10, drafts: { autosave: { interval: 100 } } },
      hooks: {
        beforeChange: [
          async ({ data, operation }) => {
            // スラッグを自動生成
            if (operation === 'create' && !data.slug) {
              data.slug = data.title
                .toLowerCase()
                .replace(/[^a-z0-9぀-龥]/g, '-')
                .replace(/-+/g, '-')
            }
            return data
          },
        ],
        afterChange: [
          async ({ doc }) => {
            // Next.js ISR キャッシュを再検証
            if (doc.status === 'published') {
              await fetch(`${process.env.FRONTEND_URL}/api/revalidate?path=/articles/${doc.slug}`)
            }
          },
        ],
      },
      fields: [
        { name: 'title', type: 'text', required: true },
        { name: 'slug', type: 'text', unique: true, index: true },
        { name: 'status', type: 'select', options: ['draft', 'review', 'published'], defaultValue: 'draft' },
        { name: 'content', type: 'richText', editor: lexicalEditor() },
        { name: 'coverImage', type: 'upload', relationTo: 'media' },
        { name: 'publishedAt', type: 'date' },
        { name: 'author', type: 'relationship', relationTo: 'users' },
        {
          name: 'seo', type: 'group', fields: [
            { name: 'title', type: 'text' },
            { name: 'description', type: 'textarea' },
          ],
        },
      ],
    },
  ],
})

Directus

2004年公開(現在はv10+)、TypeScript製のOSSです。GitHubスター28k+。既存SQLデータベースを直接ラップしてAdminパネルとAPIを即座に生成するデータプラットフォームです。PostgreSQL・MySQL・MariaDB・SQLite・MSSQL・OracleDBに対応し、既存データベースをゼロコードでAPIに変えられます。

# Directus Docker Compose セットアップ
cat > docker-compose.yml << 'EOF'
version: "3.8"
services:
  directus:
    image: directus/directus:11.0
    restart: unless-stopped
    ports:
      - "8055:8055"
    environment:
      SECRET: ${DIRECTUS_SECRET}
      DB_CLIENT: pg
      DB_HOST: postgres
      DB_PORT: 5432
      DB_DATABASE: directus
      DB_USER: directus
      DB_PASSWORD: ${DB_PASSWORD}
      ADMIN_EMAIL: admin@example.com
      ADMIN_PASSWORD: ${ADMIN_PASSWORD}
      STORAGE_LOCATIONS: s3
      STORAGE_S3_DRIVER: s3
      STORAGE_S3_KEY: ${AWS_ACCESS_KEY_ID}
      STORAGE_S3_SECRET: ${AWS_SECRET_ACCESS_KEY}
      STORAGE_S3_BUCKET: ${S3_BUCKET}
      STORAGE_S3_REGION: ${AWS_REGION}
      CACHE_ENABLED: "true"
      CACHE_STORE: redis
      REDIS: redis://redis:6379
    depends_on: [postgres, redis]

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: directus
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: ${DB_PASSWORD}

  redis:
    image: redis:7-alpine
EOF

docker compose up -d

機能比較表

比較項目StrapiPayloadDirectus
TypeScript First
Next.js統合✅ 最強
GraphQL
既存DB接続
GUI スキーマ
GitHub Stars64k+33k+28k+

ヘッドレスCMSはDevOpsカテゴリ/categories/devopsのS3/MinIOで画像・メディアを管理して、CloudflareやNginxでCDN配信するアーキテクチャが本番運用のベストプラクティスです。LLM Toolsカテゴリ/categories/llm-toolsのClaude APIと組み合わせて「記事ドラフト→AIレビュー→SEOメタ自動生成→公開」の完全自動化コンテンツパイプラインを構築できます。

FAQ

Q. Strapi v4とv5の主な変更点は?

A. v5でDocument Service APIへの移行・Draft & Publish v2・TypeScriptの型改善が行われました。主な変更: ①Entity Service APIが廃止→Document Service APIに統一(strapi.documents('api::article.article').findMany())②Draft/Publishがドキュメント単位からコンテンツタイプ単位に変更③プラグインAPIの大幅リファクタリング④Strapi Cloud(SaaS)との統合強化。v4からv5の移行: npx @strapi/upgrade latestコマンドで自動コード変換(一部手動対応が必要)。新規プロジェクトはv5一択です。

Q. Payload CMSをNext.js App Routerと同一プロジェクトに統合するには?

A. create-payload-appでNext.js統合テンプレートを選択すると最もスムーズです。①npx create-payload-app@latestWebsite templateを選択②src/app/(payload)/配下にPayloadのAdmin UIが生成③src/payload.config.tsでコレクション定義④Next.jsのServer Componentからpayload.find({ collection: 'articles' })で直接データ取得(APIコール不要)⑤ビルド時にnext build一発でCMS+フロントエンドを同時デプロイ。利点: サーバーサイドレンダリング時にPayload LocalAPIを直接呼び出してネットワークレイテンシ0でコンテンツを取得できます。

Q. Directusで既存のPostgreSQLテーブルを管理UIに接続するには?

A. Directus起動時に既存DBのURLを設定するだけで自動検出されます。手順: ①docker-composeのDB_CLIENT: pgと既存DBの接続情報を設定②起動後にDirectus AdminパネルでCollections→既存テーブルが一覧表示される③フィールドタイプ・バリデーション・リレーションを管理UIから設定④Directus CLIでdirectus schema snapshotdirectus schema applyでスキーマをGit管理。注意: Directusはテーブルにid(主キー)があることを要求します。複合主キーのテーブルはdirectus_idバーチャルカラムの設定が必要です。

Q. ヘッドレスCMSのコンテンツをNext.jsでISR配信するには?

A. CMSのWebhookでNext.jsのrevalidatePathを呼び出す設定が標準的です。①Next.js APIルートにPOST /api/revalidateを作成: revalidatePath('/articles/[slug]', 'page')②Strapi/PayloadのafterChangeフックからこのエンドポイントにHTTP POST③認証: REVALIDATION_SECRET環境変数でシークレットトークン照合④Directus: Admin→設定→Webhook→URL・イベント(create/update/delete)・HTTPメソッドPOSTを設定。SWR(stale-while-revalidate): next.config.jsrevalidate: 60(60秒キャッシュ)を設定するとWebhookなしでも最大1分後に最新コンテンツが表示されます。

まとめ

ユースケース推奨ツール
最大シェア・GUI定義・プラグイン豊富Strapi
Next.js統合・TypeScript・型安全Payload CMS
既存SQL DB・ゼロコードAPI・多DB対応Directus

関連外部リソース

他の記事も読む

Let's Build Together

OSS導入、自社だけで悩まない。

ツール選定から構築・運用・AI活用まで、オープンソースラボ運営元のClasslessが伴走します。初回のご相談は無料です。