{
  "slug": "nextjs-patterns",
  "title": "Next.js Patterns",
  "description": "How to read CMS content in Next.js — loader functions, pages, static generation, and metadata.",
  "category": "guides",
  "order": 2,
  "locale": "en",
  "translationGroup": "02c6e9b7-e6d2-43f9-b04e-eb990092d4ea",
  "helpCardId": null,
  "content": "## Reading content\n\nAll content is read server-side using `fs`:\n\n{{snippet:content-loader}}\n\n## Blog listing page\n\n{{snippet:nextjs-blog-page}}\n\n## Dynamic page with static generation\n\n```typescript\n// app/blog/[slug]/page.tsx\nimport { getCollection, getDocument } from '@/lib/content';\nimport { notFound } from 'next/navigation';\n\nexport function generateStaticParams() {\n  return getCollection('posts').map(d => ({ slug: d.slug }));\n}\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 {\n    title: doc.data._seo?.metaTitle ?? doc.data.title,\n    description: doc.data._seo?.metaDescription ?? doc.data.excerpt,\n  };\n}\n\nexport default async function PostPage({ params }: { params: Promise<{ slug: string }> }) {\n  const { slug } = await params;\n  const doc = getDocument('posts', slug);\n  if (!doc) notFound();\n\n  return (\n    <article>\n      <h1>{doc.data.title}</h1>\n      {/* Render doc.data.content with react-markdown */}\n    </article>\n  );\n}\n```\n\n## Key patterns\n\n1. **Server Components only** — content reads happen at build/request time\n2. **`generateStaticParams`** — pre-generate all pages at build time\n3. **`generateMetadata`** — SEO metadata from CMS `_seo` fields\n4. **Always filter published** — `status === 'published'` to skip drafts\n5. **Never hardcode content** — everything from CMS JSON files",
  "excerpt": "Reading content\n\nAll content is read server-side using fs:\n\n{{snippet:content-loader}}\n\n Blog listing page\n\n{{snippet:nextjs-blog-page}}\n\n Dynamic page with static generation\n\ntypescript\n// app/blog/[slug]/page.tsx\nimport { getCollection, getDocument } from '@/lib/content';\nimport { notFound } from ",
  "seo": {
    "metaTitle": "Next.js Patterns — webhouse.app Docs",
    "metaDescription": "How to read CMS content in Next.js — loader functions, pages, static generation, and metadata.",
    "keywords": [
      "webhouse",
      "cms",
      "documentation",
      "guides"
    ]
  },
  "createdAt": "2026-03-29T21:41:59.068Z",
  "updatedAt": "2026-03-30T12:04:35.755Z"
}