<!-- Generated from ja/llms-txt-cms/index.html. The canonical document is the HTML page. -->

- [ ホーム ](/ja/) 
/
- [ 作成方法 ](/ja/how-to-create/) 
/
- ヘッドレス CMS ガイド            
# ヘッドレスCMS向け`llms.txt`

ヘッドレスCMSプラットフォーム（Contentful、Sanity、Strapi、Directus）はファイルを直接配信しないため、CMSデータからビルド時にllms.txtを生成するか、サーバールートを介してリクエスト時に取得します。

最終更新: 2026年4月22日

このページの内容

- [ 基本パターン：CMS API → ビルドステップ → 静的ファイル ](#pattern)
- [ Contentfulの例 ](#contentful)
- [ Sanityの例 ](#sanity)
- [ Strapiの例 ](#strapi)
- [ Next.jsのルートハンドラーとの統合 ](#nextjs)
- [ Astro エンドポイントとの統合 ](#astro)
- [ 静的生成と動的生成 ](#static-vs-dynamic)
- [ チェックリスト ](#checklist)            
ヘッドレスCMSではなく、ホスティング型のWebサイトビルダーを使用している場合は、専用ガイドを参照してください：
[Shopify](/ja/llms-txt-shopify/), [Webflow](/ja/llms-txt-webflow/),
[Wix](/ja/llms-txt-wix/) および [Squarespace](/ja/llms-txt-squarespace/).

## 基本パターン：CMS API → ビルドステップ → 静的ファイル

ヘッドレス CMS
プラットフォームはコンテンツを管理しますが、任意のパスで任意のファイルを配信するものではありません。公開するには
`llms.txt`の場合、CMSからコンテンツを取得して自分でファイルを書き出す必要があります。次のいずれかの時点で行います：
**ビルド時** （静的な出力）または **リクエスト時** （サーバールート）。

- **CMSを照会する**、タイトル、slug、要約フィールドを持つ公開済みページを取得します。 
- **Markdown リンクにマッピング**、各項目を次の形式にします： `- [Title](https://url/): description.` 
- **ファイルを書き込むか返します**、次の場所に書き込みます: `public/llms.txt` をビルド時に書き込むか、リクエスト時にサーバールートから返します。     
注記

静的と動的の比較

静的生成はより単純で高速であり、ファイルは CDN
にキャッシュされます。動的生成（サーバールート）では、再ビルドなしで常に最新のファイルを提供できます。CMS
を使用する大半のサイトでは、毎日またはデプロイごとに再ビルドする静的生成が適切です。

## Contentfulの例

以下の [Contentful JavaScript SDK](https://github.com/contentful/contentful.js) 
Content Delivery API 経由でエントリを取得するため。このスクリプトはビルドステップ中に実行してください（例：
`package.json` スクリプトまたはCIパイプライン）で、フレームワークのビルド前に実行します。
scripts/generate-llms-txt.mjs (Contentful)    コピー     

```
// scripts/generate-llms-txt.mjs
// Contentful: fetch published doc entries and generate llms.txt at build time

import { createClient } from 'contentful';
import { writeFileSync } from 'fs';

const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});

async function generateLlmsTxt() {
// Fetch entries of content type 'docPage' sorted by display order
const entries = await client.getEntries({
content_type: 'docPage',
order: 'fields.order',
select: 'fields.title,fields.slug,fields.summary',
limit: 100,
});

const SITE_URL = process.env.SITE_URL || 'https://yoursite.com';

const links = entries.items
.map((entry) => {
const { title, slug, summary } = entry.fields;
return `- [${title}](${SITE_URL}/docs/${slug}/): ${summary ?? ''}`;
})
.join('\n');

const content = [
'# Your Site',
'',
'> One-sentence description of your product.',
'',
'## Documentation',
'',
links,
'',
'## Optional',
'',
`- [Changelog](${SITE_URL}/changelog/): Release history.`,
].join('\n');

writeFileSync('public/llms.txt', content, 'utf-8');
console.log(`Generated llms.txt with ${entries.items.length} entries.`);
}

generateLlmsTxt().catch(console.error);

```

スクリプトをビルドパイプラインに追加します。
package.json    コピー     

```
{
"scripts": {
"prebuild": "node scripts/generate-llms-txt.mjs",
"build": "next build"
}
}
```

## Sanityの例

Sanityのクエリ言語であるGROQを使用して、必要なフィールドのみを正確に取得してください。 `!(_id in path("drafts.**"))` filter により、公開済みのドキュメントのみが確実に含まれるようになります：
scripts/generate-llms-txt.mjs (Sanity)    コピー     

```
// scripts/generate-llms-txt.mjs
// Sanity: use GROQ to query published docs and generate llms.txt

import { createClient } from '@sanity/client';
import { writeFileSync } from 'fs';

const client = createClient({
projectId: process.env.SANITY_PROJECT_ID,
dataset: process.env.SANITY_DATASET || 'production',
useCdn: false, // always fetch fresh data at build time
apiVersion: '2024-01-01',
});

async function generateLlmsTxt() {
// GROQ query: fetch all published doc entries with title, slug, and summary
const docs = await client.fetch(
`*[_type == "doc" && !(_id in path("drafts.**"))] | order(order asc) {
title,
"slug": slug.current,
summary
}`
);

const SITE_URL = process.env.SITE_URL || 'https://yoursite.com';

const links = docs
.map((doc) => `- [${doc.title}](${SITE_URL}/docs/${doc.slug}/): ${doc.summary ?? ''}`)
.join('\n');

const content = [
'# Your Site',
'',
'> One-sentence description of your product.',
'',
'## Documentation',
'',
links,
].join('\n');

writeFileSync('public/llms.txt', content, 'utf-8');
console.log(`Generated llms.txt with ${docs.length} docs.`);
}

generateLlmsTxt().catch(console.error);

```

## Strapiの例

Strapiは次の場所でREST APIを公開します: `/api/:collection`。次を使用します: `fields` および `filters` 必要なフィールドだけを含む公開済み文書を取得するためのクエリパラメーター:
scripts/generate-llms-txt.mjs (Strapi)    コピー     

```
// scripts/generate-llms-txt.mjs
// Strapi v4/v5: fetch published articles via REST API and generate llms.txt

import { writeFileSync } from 'fs';

const STRAPI_URL = process.env.STRAPI_URL || 'http://localhost:1337';
const STRAPI_TOKEN = process.env.STRAPI_API_TOKEN;
const SITE_URL = process.env.SITE_URL || 'https://yoursite.com';

async function generateLlmsTxt() {
// Fetch published docs, adjust the collection slug and fields as needed
const res = await fetch(
`${STRAPI_URL}/api/docs?fields[0]=title&fields[1]=slug&fields[2]=summary&filters[publishedAt][$notNull]=true&pagination[limit]=100`,
{
headers: STRAPI_TOKEN ? { Authorization: `Bearer ${STRAPI_TOKEN}` } : {},
}
);

if (!res.ok) throw new Error(`Strapi API error: ${res.status}`);
const { data } = await res.json();

const links = data
.map((item) => {
const { title, slug, summary } = item.attributes ?? item; // v4 vs v5
return `- [${title}](${SITE_URL}/docs/${slug}/): ${summary ?? ''}`;
})
.join('\n');

const content = [
'# Your Site',
'',
'> One-sentence description of your product.',
'',
'## Documentation',
'',
links,
].join('\n');

writeFileSync('public/llms.txt', content, 'utf-8');
console.log(`Generated llms.txt with ${data.length} entries.`);
}

generateLlmsTxt().catch(console.error);

```

Strapi v4 はレスポンスデータを `attributes` オブジェクト内にあります。Strapi v5はフィールドを最上位に返します。この例ではフォールバックを使って両方に対応しています。

## Next.jsのルートハンドラーとの統合

完全な再構築を行わずにファイルを常に同期させたい場合は、Next.js App Routerのルート
ハンドラーを使用してください。 `revalidate` を希望するTTLに設定します。Next.jsはレスポンスをキャッシュし、
バックグラウンドで再生成します：
app/llms.txt/route.ts (Next.js + Contentful)    コピー     

```
// app/llms.txt/route.ts
// Next.js App Router, fetch from CMS at request time (or cache with revalidate)

import { NextResponse } from 'next/server';
import { createClient } from 'contentful';

// Cache for 1 hour (Next.js incremental static regeneration)
export const revalidate = 3600;

const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID!,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
});

export async function GET() {
const entries = await client.getEntries({
content_type: 'docPage',
order: 'fields.order',
select: 'fields.title,fields.slug,fields.summary',
limit: 100,
});

const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'https://yoursite.com';

const links = entries.items
.map((e: any) => `- [${e.fields.title}](${SITE_URL}/docs/${e.fields.slug}/): ${e.fields.summary ?? ''}`)
.join('\n');

const body = [
'# Your Site',
'',
'> One-sentence description.',
'',
'## Documentation',
'',
links,
].join('\n');

return new NextResponse(body, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
},
});
}

```

## Astro エンドポイントとの統合

Astroでは、 `src/pages/llms.txt.ts` エンドポイントと `export const prerender = true` を使い、ビルド時にファイルを生成します。Astroは次の実行中にCMS
APIを呼び出します： `astro build` を実行し、静的ファイルを次へ書き込みます： `dist/llms.txt`:
src/pages/llms.txt.ts (Astro + Sanity)    コピー     

```
// src/pages/llms.txt.ts
// Astro endpoint, fetch from CMS at build time (static generation)

import type { APIRoute } from 'astro';
import { createClient } from '@sanity/client';

// This endpoint is pre-rendered at build time
export const prerender = true;

const sanity = createClient({
projectId: import.meta.env.SANITY_PROJECT_ID,
dataset: import.meta.env.SANITY_DATASET || 'production',
useCdn: false,
apiVersion: '2024-01-01',
});

export const GET: APIRoute = async () => {
const docs = await sanity.fetch(
`*[_type == "doc" && !(_id in path("drafts.**"))] | order(order asc) {
title, "slug": slug.current, summary
}`
);

const SITE_URL = import.meta.env.SITE_URL || 'https://yoursite.com';

const links = docs
.map((doc: any) => `- [${doc.title}](${SITE_URL}/docs/${doc.slug}/): ${doc.summary ?? ''}`)
.join('\n');

const body = [
'# Your Site',
'',
'> One-sentence description of your product.',
'',
'## Documentation',
'',
links,
].join('\n');

return new Response(body, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
};

```

## 静的生成と動的生成

- **静的（ビルド時）**、より高速（CDN キャッシュ）、より簡単で、ランタイムの CMS
依存がありません。コンテンツの変更頻度が低い場合や、変更のたびにデプロイする場合に適しています。 
- **動的（サーバールート）**は常に最新のCMSコンテンツを反映します。デプロイの合間にコンテンツが頻繁に変わる場合や、コンテンツ変更時に再ビルドを起動できない場合に最適です。
`Cache-Control` ヘッダーを設定し、リクエストのたびに CMS APIへの過度な負荷を回避する。   
## チェックリスト

- スクリプトまたはエンドポイントによる取得のみ **公開済み** コンテンツ（下書きではないもの）。 
- 生成されたすべてのURLは **絶対URL** (`https://`). 
- ファイルがH1をちょうど1つだけ先頭に含むこと。 
- H1の直後に引用ブロック形式の要約があること。 
- 各セクションに少なくとも一つのリンクがある。 
- ファイルが20 KB未満であること（すべての項目を流し込まず、厳選してください）。 
- ビルドステップがフレームワークのビルド前に実行される（`prebuild` スクリプトまたはCIステップ）。 
- 次で検証済み： [llmtxt.info/validator/](/ja/validator/) （各デプロイ後）。   
## 関連ガイド

- [llms.txtの作成方法](/ja/how-to-create/)、テンプレートとデプロイガイド。 
- [Next.js ガイド](/ja/llms-txt-nextjs/)、App Router、静的生成。 
- [Astroガイド](/ja/llms-txt-astro/)、コンテンツコレクション、エンドポイント。 
- [llms.txt フォーマットリファレンス](/ja/llms-txt-format/)、仕様の詳細。 
- [バリデータ](/ja/validator/) · [ジェネレーター](/ja/generator/).        
## ソース

- [ llmstxt.org、コミュニティによる提案 ](https://llmstxt.org/)
- [ Contentful JavaScript SDK ](https://github.com/contentful/contentful.js)
- [ Sanity GROQ リファレンス ](https://www.sanity.io/docs/content-lake/how-queries-work)
- [ Strapi REST APIドキュメント ](https://docs.strapi.io/cms/api/rest)
