編集チームではApp Routerで、静的app/robots.txtと生成app/robots.tsまたはapp/robots.jsを要件に応じて選びます。
静的で足りる場合は単純にします
固定ポリシーならランタイム依存を増やさない構成を優先します。
生成時はMetadataRoute.Robotsを使います
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return { rules: { userAgent: '*', allow: '/' }, sitemap: 'https://example.com/sitemap.xml' }
}
cacheとdynamic動作を確認します
生成metadata routeのcacheは実装によって変わります。コードだけでなく公開レスポンスも確認します。
previewは別のアクセス制御で守ります
非公開previewには認証を使い、Sitemap:がpreview hostを指していないかも確認します。
デプロイ後に検証します
/robots.txtを開き、validatorとtesterで本番挙動を確認します。
現在のApp Routerの前提
Next.jsは静的な app/robots.txt と、MetadataRoute.Robots を返す app/robots.ts / app/robots.js をサポートします。生成metadata routeは実装によってcacheされるため、framework versionと公開レスポンスを確認し、毎requestで再計算されると決めつけません。
ポリシーが固定なら静的ファイルを優先します。複数crawler groupや環境依存hostnameなど生成に意味がある場合だけ動的にします。robots routeから外部APIへ依存させず、設定サービス障害でcrawl policyまで壊れないようにします。
Deploy時に確認する失敗例
preview domainがSitemapへ入る、middleware/proxyが /robots.txt を捕捉する、静的ファイルと生成routeが競合する、古いcache、staging branchがproductionで選ばれる、といったケースをsmoke testします。status、content-type、body、sitemap hostnameを公開hostで直接確認します。
Staticとgeneratedの選択理由を明確にします
policyが全deployで同じなら app/robots.txt の方が単純で監査しやすくなります。app/robots.ts を使うのは、複数crawler group、環境ごとのproduction hostname、複数sitemapなどcodeで管理する明確な理由がある場合です。runtimeで外部APIへ問い合わせる設計は避け、crawler policyが別serviceのtimeoutに巻き込まれないようにします。
generated routeを使う場合、Next.jsのcache挙動とdynamic APIの利用有無も確認します。codeを変更したのにlive responseが変わらないとき、まずframework cache、Vercel/CDN、middleware/proxyの順に切り分けます。metadata fileと通常Route Handlerの所有関係も確認し、静的fileとgenerated routeを同時に置かないようにします。
Deploy smoke testへ組み込みます
本番build後に /robots.txt を自動または手動で取得し、200 status、text content-type、想定User-agent group、Sitemapのproduction hostを確認します。preview deploymentでも同じ確認を行い、production向けURLがpreviewへ漏れていないかを見ます。最終的にはvalidatorとtesterで代表URLを確認し、TypeScriptが正しいだけで終了しません。
Route ownershipを一つにします
同じprojectでstatic robots.txtとgenerated metadata routeを併用すると、将来のrefactorでどちらが正しいsourceか分からなくなります。実装方式を一つに決め、READMEやcode commentで理由を残します。