Data Fetching
Documentation content can be sourced from various locations — local files, a CMS, a Git repository, or an API. Next.js 16 provides flexible patterns for fetching and caching this content.
Server Components
Server Components are the default in the App Router, making them ideal for fetching documentation content at build or request time without shipping additional JavaScript to the client.
app/docs/[slug]/page.tsx
import { getDocBySlug } from "@/lib/docs"
interface Props {
params: Promise<{ slug: string }>
}
export default async function DocPage({ params }: Props) {
const { slug } = await params
const doc = await getDocBySlug(slug)
return (
<article className="docs-prose">
<h1>{doc.title}</h1>
<div dangerouslySetInnerHTML={{ __html: doc.content }} />
</article>
)
}Fetching content
For markdown-based documentation, fetch and parse content on the server:
lib/docs.ts
import fs from "node:fs/promises"
import path from "node:path"
import matter from "gray-matter"
const DOCS_DIR = path.join(process.cwd(), "content/docs")
export async function getDocBySlug(slug: string) {
const filePath = path.join(DOCS_DIR, `${slug}.mdx`)
const source = await fs.readFile(filePath, "utf-8")
const { data, content } = matter(source)
return {
title: data.title as string,
description: data.description as string,
content,
}
}Static content
For fully static documentation, use the "use cache" directive to pre-render pages at build time:
app/docs/[slug]/page.tsx
"use cache"
export default async function DocPage({ params }: Props) {
const { slug } = await params
const doc = await getDocBySlug(slug)
return <article>{/* ... */}</article>
}Cache Components
Next.js 16 introduces Cache Components with the
"use cache" directive. This allows fine-grained control over which parts of your page are cached.Client-side data
For interactive features like search or live previews, use SWR to fetch data on the client:
components/search.tsx
"use client"
import useSWR from "swr"
const fetcher = (url: string) => fetch(url).then(r => r.json())
export function SearchResults({ query }: { query: string }) {
const { data, isLoading } = useSWR(
query ? `/api/search?q=${query}` : null,
fetcher
)
if (isLoading) return <p>Searching...</p>
return <ul>{data?.results.map(/* ... */)}</ul>
}