Express.js 向け llms.txt

Expressは最も広く使われているNode.js Webフレームワークです。llms.txtの配信は簡単で、静的ファイルならexpress.static()、動的生成なら専用のGETルートを使用できます。

最終更新:

選択肢1:express.static() を使った静的ファイル

アプリですでに express.static() 配信するための public/ フォルダに、単にドラッグ&ドロップしてください llms.txt をそのフォルダーに入れます。Expressはそれを /llms.txt 。追加のコードは不要です。

server.js, static file approach
// server.js
const express = require('express');
const app = express();

// Serve everything in ./public/ at the root URL.
// If public/llms.txt exists, it is available at /llms.txt automatically.
app.use(express.static('public'));

app.listen(3000, () => console.log('Listening on http://localhost:3000'));

// Project structure:
// your-express-app/
// ├── public/
// │   └── llms.txt   ← add this
// └── server.js

Expressは自動的に Content-Typetext/plain.txt で配信されるファイルには、 express.static(). を追加するには、 Cache-Control ヘッダーを追加するには、 maxAge 静的オプションで

Cache-Control with express.static()
app.use(express.static('public', { maxAge: '1h' }));

オプション 2:専用の GET ルート

ヘッダーとコンテンツを完全に制御するには、専用のルートを追加してください。これは、コンテンツが実行時にデータベースやAPIルートレジストリから生成される場合にも、適切な アプローチです。

server.js, GET route
// server.js, dedicated GET route
const express = require('express');
const app = express();

const llmsContent = `# Your Site

> One-sentence description of what your site or product does.

## Documentation

- [Getting Started](https://yoursite.com/docs/start): Install and configure in minutes.
- [API Reference](https://yoursite.com/docs/api): Full endpoint catalog with examples.

## Product

- [Overview](https://yoursite.com/product): Core features and capabilities.
- [Pricing](https://yoursite.com/pricing): Plans and billing details.

## Optional

- [Changelog](https://yoursite.com/changelog): Release history.
- [GitHub](https://github.com/your-org/your-repo): Source code.
`;

app.get('/llms.txt', (req, res) => {
  res.type('text/plain');
  res.set('Cache-Control', 'public, max-age=3600, stale-while-revalidate=86400');
  res.send(llmsContent);
});

app.listen(3000);

このルートは 前に 包括的なルートハンドラーや 404 ミドルウェアがない限り、 Express はそこに到達することはありません。

TypeScript版

プロジェクトでTypeScriptと @types/expressでは、暗黙的な any エラー:

server.ts, TypeScript
// server.ts, TypeScript version with typed Request/Response
import express, { Request, Response } from 'express';

const app = express();

const llmsContent = `# Your Site

> One-sentence description of your product or service.

## Documentation

- [Getting Started](https://yoursite.com/docs/start): Quick setup guide.
- [API Reference](https://yoursite.com/docs/api): Full endpoint catalog.

## Optional

- [Changelog](https://yoursite.com/changelog): Release history.
`;

app.get('/llms.txt', (req: Request, res: Response): void => {
  res.set({
    'Content-Type': 'text/plain; charset=utf-8',
    'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
  });
  res.send(llmsContent);
});

app.listen(3000, () => console.log('Server running on http://localhost:3000'));

ルートメタデータからの動的生成

大規模なアプリケーションの場合は、 publicRoutes 配列をルート定義と並べて管理します。 /llms.txt ハンドラーはこの配列をMarkdownリンクへ変換し、ファイルと実際のルートの同期を保ちます。

server.js, dynamic generation
// server.js, generate llms.txt dynamically from route metadata
const express = require('express');
const app = express();

// Define your public routes with metadata
const publicRoutes = [
  { title: 'Getting Started', path: '/docs/start', description: 'Install and configure in minutes.' },
  { title: 'API Reference', path: '/docs/api', description: 'Full endpoint catalog with examples.' },
  { title: 'Authentication', path: '/docs/auth', description: 'OAuth 2.0 and API key setup.' },
  { title: 'Webhooks', path: '/docs/webhooks', description: 'Event payloads and retry policy.' },
  { title: 'Pricing', path: '/pricing', description: 'Plans and billing details.' },
];

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

app.get('/llms.txt', (req, res) => {
  const links = publicRoutes
    .map((r) => `- [${r.title}](${SITE_URL}${r.path}): ${r.description}`)
    .join('\n');

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

  res.set({
    'Content-Type': 'text/plain; charset=utf-8',
    'Cache-Control': 'public, max-age=3600, stale-while-revalidate=86400',
  });
  res.send(body);
});

app.listen(3000);

設定するのは SITE_URL ローカル、ステージング、本番の環境で同じコードが動くよう、環境変数として設定します。

Cache-Control ヘッダー

必ず Cache-Control ヘッダー。一時間のTTLと stale-while-revalidate が妥当なデフォルトです。リバースプロキシやCDN(nginx、Cloudflare、AWS CloudFront)がレスポンスをキャッシュし、バックグラウンドで再検証しながら古いコンテンツを配信できます。

Recommended Cache-Control
res.set('Cache-Control', 'public, max-age=3600, stale-while-revalidate=86400');

Expressの前段でCDNを使用する場合は、そのCDNが次を尊重することを確認してください: Cache-Control をオリジンから受け取ります。Cloudflareはデフォルトで尊重しますが、AWS CloudFrontではオリジンのヘッダーを通過させるキャッシュポリシーが必要です。

検証

サーバーを起動したら、ファイルが正しく配信されていることを確認します。

Local verification
# Check headers
curl -I http://localhost:3000/llms.txt
# Expected:
# HTTP/1.1 200 OK
# Content-Type: text/plain; charset=utf-8
# Cache-Control: public, max-age=3600

# Check content
curl http://localhost:3000/llms.txt | head -5
# Should print:  # Your Site

デプロイ後、公開URLに対して同じ確認を行い、そのURLを llms.txt バリデーター で仕様への完全な準拠を確認します。

リリース前のチェックリスト

  • ファイルの配信先: /llms.txt200 OK.
  • Content-Type: text/plain; charset=utf-8 が設定されていること。
  • Cache-Control ヘッダーが存在します。
  • ファイルの先頭にH1見出しがちょうど1つあること。
  • H1の直後にブロッククォートの要約を配置する。
  • すべてのURLは絶対パスである(https://).
  • ルートがcatch-allまたは404ハンドラーより前に登録されている。
  • バリデーターでエラーが返されないこと: llmtxt.info/validator/

関連ガイド

ソース