{
  "slug": "nextjs-helpers",
  "title": "Next.js SEO Helpers",
  "description": "Drop-in sitemap, robots.txt, llms.txt, metadata, JSON-LD, RSS feed, and static params — all auto-generated from CMS content via @webhouse/cms/next.",
  "category": "guides",
  "order": 12,
  "locale": "en",
  "translationGroup": "73f85c7e-afac-4aa9-9c58-c3cb8801e489",
  "helpCardId": null,
  "content": "## Overview\n\n`@webhouse/cms/next` is a sub-path export that gives your Next.js site full SEO and discoverability — sitemap, robots.txt, llms.txt, metadata, JSON-LD, RSS feed — all auto-generated from CMS content and `_seo` fields.\n\nNo new logic needed. It wraps the existing CMS build pipeline for Next.js consumption.\n\n```bash\n# Already included with @webhouse/cms — no extra install\nimport { cmsSitemap, cmsRobots, cmsMetadata } from '@webhouse/cms/next';\n```\n\n## Sitemap\n\nAuto-generates `sitemap.xml` with hreflang alternates for multi-locale sites.\n\n```typescript\n// app/sitemap.ts\nimport { cmsSitemap } from '@webhouse/cms/next';\n\nexport default cmsSitemap({\n  baseUrl: 'https://example.com',\n  collections: [\n    { name: 'pages', urlPrefix: '/' },\n    { name: 'posts', urlPrefix: '/blog' },\n  ],\n  // Optional i18n\n  locales: ['en', 'da'],\n  defaultLocale: 'en',\n  localeStrategy: 'prefix-other',\n});\n```\n\n**Options:**\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `baseUrl` | `string` | — | Site URL (no trailing slash) |\n| `collections` | `SitemapCollection[]` | — | Collections to include |\n| `locales` | `string[]` | — | Available locales for hreflang |\n| `defaultLocale` | `string` | — | Default locale (gets x-default) |\n| `localeStrategy` | `string` | `\"prefix-other\"` | URL locale strategy |\n| `changeFrequency` | `string` | `\"weekly\"` | Default change frequency |\n| `defaultPriority` | `number` | `0.7` | Default priority |\n\n## Robots.txt\n\nGenerates `robots.txt` with AI bot management strategies from F112 GEO.\n\n```typescript\n// app/robots.ts\nimport { cmsRobots } from '@webhouse/cms/next';\n\nexport default cmsRobots({\n  baseUrl: 'https://example.com',\n  strategy: 'maximum',  // or 'balanced', 'restrictive', 'custom'\n});\n```\n\n**Strategies:**\n\n| Strategy | Behavior |\n|----------|----------|\n| `maximum` | Allow all bots including AI crawlers |\n| `balanced` | Allow search engines, block aggressive AI scrapers |\n| `restrictive` | Block all AI bots, allow only search engines |\n| `custom` | Your own rules via `customRules` |\n\n## llms.txt\n\nMachine-readable site index for AI agents — helps AI crawlers understand your site structure.\n\n```typescript\n// app/llms.txt/route.ts\nimport { cmsLlmsTxt } from '@webhouse/cms/next';\n\nexport const GET = cmsLlmsTxt({\n  baseUrl: 'https://example.com',\n  siteTitle: 'My Site',\n  siteDescription: 'A great site built with webhouse.app',\n  collections: [\n    { name: 'posts', label: 'Blog Posts', urlPrefix: '/blog' },\n  ],\n});\n```\n\nFor the full content export (all document text):\n\n```typescript\n// app/llms-full.txt/route.ts\nimport { cmsLlmsFullTxt } from '@webhouse/cms/next';\n\nexport const GET = cmsLlmsFullTxt({\n  baseUrl: 'https://example.com',\n  siteTitle: 'My Site',\n  collections: [{ name: 'posts', label: 'Blog Posts', urlPrefix: '/blog' }],\n});\n```\n\n## Metadata\n\nExtracts `_seo` fields from any CMS document into a Next.js `Metadata` object.\n\n```typescript\n// app/blog/[slug]/page.tsx\nimport { cmsMetadata } from '@webhouse/cms/next';\nimport { getDocument } from '@/lib/content';\n\nexport async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {\n  const { slug } = await params;\n  const doc = getDocument('posts', slug);\n  if (!doc) return {};\n  return cmsMetadata({\n    baseUrl: 'https://example.com',\n    siteName: 'My Site',\n    doc,\n    collection: 'posts',\n    urlPrefix: '/blog',\n  });\n}\n```\n\n**What it generates:**\n\n- `title` from `_seo.metaTitle` or `data.title`\n- `description` from `_seo.metaDescription` or `data.excerpt`\n- `keywords` from `_seo.keywords`\n- `openGraph` with image, site name, type (article/website), published time\n- `alternates.canonical` from `_seo.canonical` or computed URL\n- `robots` from `_seo.robots`\n- Geo meta tags from map fields (F96)\n\n## JSON-LD\n\nExtracts structured data from `_seo.jsonLd` for search engine rich results.\n\n```typescript\n// In your page component\nimport { cmsJsonLd } from '@webhouse/cms/next';\n\nexport default function BlogPost({ doc }) {\n  const jsonLd = cmsJsonLd(doc);\n  return (\n    <article>\n      {jsonLd && (\n        <script\n          type=\"application/ld+json\"\n          dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}\n        />\n      )}\n      <h1>{doc.data.title}</h1>\n    </article>\n  );\n}\n```\n\nCMS admin generates JSON-LD from 12 schema templates (Article, BlogPosting, FAQ, Product, LocalBusiness, etc.) via the SEO panel.\n\n## RSS Feed\n\nAuto-generates RSS 2.0 XML feed from CMS content.\n\n```typescript\n// app/feed.xml/route.ts\nimport { cmsFeed } from '@webhouse/cms/next';\n\nexport const GET = cmsFeed({\n  baseUrl: 'https://example.com',\n  title: 'My Blog',\n  description: 'Latest posts from My Blog',\n  collections: [{ name: 'posts', urlPrefix: '/blog' }],\n  maxItems: 50,\n});\n```\n\n## generateStaticParams\n\nFactory for Next.js `generateStaticParams()` — returns all published slugs for a collection.\n\n```typescript\n// app/blog/[slug]/page.tsx\nimport { cmsGenerateStaticParams } from '@webhouse/cms/next';\n\nexport const generateStaticParams = cmsGenerateStaticParams({\n  collection: 'posts',\n  paramName: 'slug',  // default\n});\n```\n\n## Fly.io Deployment\n\nNext.js boilerplates include a production-ready `Dockerfile` for Fly.io deploy:\n\n```bash\n# Deploy via CLI\nflyctl deploy --remote-only --ha=false\n```\n\nOr use the **Deploy tab** in CMS admin — it auto-detects the Dockerfile and deploys to Fly.io with:\n\n- Region: `arn` (Stockholm)\n- Port: 3000\n- Memory: 512MB\n- Auto-generated `fly.toml`\n\nThe Dockerfile uses Next.js standalone output (`output: \"standalone\"` in `next.config.ts`) for minimal image size. Content files are copied into the image for `fs`-based reads at runtime.\n\n## Complete Setup\n\nHere's what a fully SEO-optimized Next.js site looks like:\n\n```text\napp/\n  sitemap.ts          ← cmsSitemap()\n  robots.ts           ← cmsRobots()\n  llms.txt/route.ts   ← cmsLlmsTxt()\n  llms-full.txt/route.ts ← cmsLlmsFullTxt()\n  feed.xml/route.ts   ← cmsFeed()\n  blog/\n    [slug]/page.tsx   ← cmsMetadata() + cmsJsonLd()\n  [slug]/page.tsx     ← cmsMetadata() + cmsJsonLd()\n```\n\nAll of this is pre-configured in both the `nextjs-boilerplate` and `nextjs-github-boilerplate` templates.",
  "excerpt": "Overview\n\n@webhouse/cms/next is a sub-path export that gives your Next.js site full SEO and discoverability — sitemap, robots.txt, llms.txt, metadata, JSON-LD, RSS feed — all auto-generated from CMS content and seo fields.\n\nNo new logic needed. It wraps the existing CMS build pipeline for Next.js co",
  "seo": {
    "metaTitle": "Next.js SEO Helpers — webhouse.app Docs",
    "metaDescription": "Drop-in sitemap, robots.txt, llms.txt, metadata, JSON-LD, RSS feed for Next.js sites — auto-generated from @webhouse/cms content.",
    "keywords": [
      "webhouse",
      "cms",
      "next.js",
      "seo",
      "sitemap",
      "metadata",
      "json-ld",
      "robots.txt",
      "llms.txt"
    ]
  },
  "createdAt": "2026-04-01T10:00:00.000Z",
  "updatedAt": "2026-04-01T10:00:00.000Z"
}