See Agility CMS in action. Watch a product demo
Rendering & Data Fetching with Next.js and Agility CMS
Next.js can render a page in several ways — fully static, dynamic per request, or a mix of both. In the App Router (Next.js 13+, and what the Agility Next.js Starter uses), you no longer choose a strategy with getStaticProps / getServerSideProps. Instead, how you fetch and cache data decides how a route renders. This guide maps the classic strategies onto the App Router and shows the recommended approach with Agility.
Using the Pages Router?
getStaticProps,getServerSideProps, andgetStaticPathsstill work there. Everything below is for the App Router, which is the recommended model for new Agility sites.
Everything is a Server Component by default
Pages and components are React Server Components — they render on the server, ship zero JavaScript by default, and can await data directly. There's no getStaticProps; you fetch right inside the component:
// app/[locale]/[...slug]/page.tsx
export default async function Page({ params }) {
const { locale, slug } = await params
const { page } = await getAgilityPage({ slug, locale, preview: false })
const Template = getPageTemplate(page.templateName)
return <Template page={page} />
}
Static or dynamic? Decide per data read
| Pages Router | App Router (recommended with Agility) |
|---|---|
getStaticProps + revalidate (ISR) | async Server Component + "use cache" + cacheTag, revalidated on publish |
getStaticPaths | generateStaticParams |
getServerSideProps | async Server Component that reads request data (connection() / cookies() / draftMode()), or export const dynamic = "force-dynamic" |
on-demand ISR (res.revalidate) | revalidateTag(tag, "max") from the publish webhook |
For a content site, the default you want is static + tag-based revalidation — static-fast pages that refresh the instant an editor publishes. The full setup (cacheComponents, "use cache", cacheTag, the revalidate webhook) is covered in Caching with Next.js and Agility.
Prerender every CMS page: generateStaticParams
Replace getStaticPaths with generateStaticParams, driven by the Agility sitemap:
export async function generateStaticParams() {
const sitemap = await getSitemapFlat({ locale: "en-us", preview: false })
return Object.values(sitemap).map((node) => ({
slug: node.path.split("/").filter(Boolean),
}))
}
Force dynamic (per-request) rendering when you need it
Sometimes a page genuinely must render per request — personalization, auth, or reading the incoming request. Opt a single read into request time with connection():
import { connection } from "next/server"
export default async function Page() {
await connection() // this render is now dynamic
const data = await fetchPerRequestData()
// ...
}
…or make the whole route dynamic:
export const dynamic = "force-dynamic"
Reading cookies(), headers(), or draftMode() also opts a route into dynamic rendering automatically.
Preview is always dynamic
Agility preview / draft rendering must never be cached, so editors always see their latest work. The pattern is a preview-aware fetch that calls connection() and skips the cache — see the preview branch in the caching guide. Preview itself is toggled with Next's draftMode().
Streaming & Partial Prerendering
With Cache Components enabled, Next prerenders the static shell of a route and streams the dynamic parts at request time. Wrap any request-time or slow region in <Suspense> so the rest of the page ships instantly:
<Suspense fallback={<HeaderSkeleton />}>
<SiteHeader /> {/* fetches per-request / preview data */}
</Suspense>
This is also what keeps a connection() call from turning the whole route dynamic — only the Suspense boundary around it becomes request-time.
Recommendation
For an Agility-powered content site, default to static Server Components with "use cache" + tag-based revalidation. You get static-fast pages, instant updates when editors publish, and you reach for dynamic rendering (connection() / force-dynamic) only where a page truly depends on the incoming request. For the complete caching setup, read Caching with Next.js and Agility.