
Preview Mode in Next.js with a Headless CMS

One of the awkward tensions in static or heavily cached sites is editorial preview.
The whole point of a published site is that it serves stable, production‑ready content efficiently. The whole point of an editor preview is that it shows content which is not yet published. Those two needs pull in opposite directions, and headless CMS projects feel that tension quickly.
Next.js Preview Mode is a very practical answer to the problem.
It lets a statically generated site behave differently for previewing editors without changing the published experience for everyone else.
The Core Idea
Normally, a statically generated page shows published content.
When Preview Mode is enabled for a request, Next.js can instead render draft or preview content for that visitor. This is usually controlled through preview cookies and an API route that turns preview on.
That means:
- normal visitors keep getting the published site
- authorised preview users can see unpublished changes
This is exactly the balance most editorial teams need.
Why CMS Projects Need This
A content editor does not want to publish blind.
They usually want to:
- save a draft
- click preview
- see the page as it would appear on the site
- continue editing before publishing
In traditional CMS platforms, that workflow was often built into the same system managing the live pages. In a headless setup, the site and the CMS are separate systems, so preview needs a deliberate bridge.
Preview Mode becomes that bridge.
The Usual Flow Starts with an API Route
A common setup is an API route that enables preview:
import type { NextApiRequest, NextApiResponse } from 'next';const previewHandler = ( request: NextApiRequest, response: NextApiResponse,): void => { response.setPreviewData({}); response.redirect(request.query.slug as string);};export default previewHandler;This turns Preview Mode on and redirects the editor to the relevant page.
After That, Page Data Fetching Can Check Preview State
Inside page data fetching, we can inspect whether the request is in preview mode:
import type { GetStaticProps } from 'next';export const getStaticProps: GetStaticProps = async ({ preview = false }) => { const article = preview ? await fetchDraftArticle() : await fetchPublishedArticle(); return { props: { article, preview, }, };};This is the elegant part of the feature. The published build remains static, but preview requests can follow a different content path.
The Published Site Stays Clean
That separation is why the feature is so useful operationally.
We do not need to turn the whole site into request‑time rendering just because editors need previews occasionally. Published traffic can still benefit from static generation, while preview traffic opts into a more dynamic pathway.
That is a very strong fit for headless CMS work.
That same balance mattered on the Nando’s replatform, where editorial workflows across recipes, products, restaurant pages, and wider content needed a stable public platform without making editors work blind.
Security Matters Here
Preview access should not be an unguarded switch anyone can flip.
Most real implementations include some kind of validation, such as:
- a shared secret token
- CMS‑generated preview URLs
- route validation before redirecting
Without that, draft content risks being exposed more widely than intended.
So although Preview Mode feels editorial on the surface, it is also a small security feature and should be treated with appropriate care.
The Preview Content Source May Differ from the Published One
This is another reason the feature works well with headless CMS setups.
The published site may read only production‑ready entries.
Preview mode may read:
- drafts
- unpublished revisions
- staging API responses
- editor‑facing content endpoints
The page component itself does not necessarily need to know why the content differs. It just receives the appropriate data for the current mode.
A Clear Preview Indicator is Often a Good Idea
Editors should usually know they are in preview mode.
That can mean a banner, badge, or small bit of UI that says:
- you are viewing draft content
- preview is active
- click here to exit preview
This avoids the slightly unnerving experience of not being sure whether you are looking at the published site or a draft version.
Exiting Preview Should Be Easy Too
The workflow is smoother when the site provides a clear route back to normal mode, usually via another small API route that clears preview data and redirects the user back.
Good editorial preview is not just about turning preview on. It is about making the full cycle easy:
- enter preview
- review draft changes
- exit preview
This is One of the Best Examples of Hybrid Behaviour in Next.js
Next.js often shines when a site is mostly static but occasionally needs dynamic behaviour for specific users or specific routes.
Preview Mode is a very clean example of that philosophy. It does not throw away the benefits of static generation. It creates an escape hatch for a legitimate workflow that static generation alone cannot satisfy.
CMS Preview is About Confidence
Editors want to know:
- what the content looks like in context
- whether the layout still works
- whether links, headings, and images behave properly
Preview Mode supports that confidence without forcing the public site into the same rendering mode.
Draft Content and Public Content Can Coexist
Preview Mode in Next.js is valuable because it respects both sides of a headless CMS workflow. Editors need to see draft content before publishing. The public site needs to stay stable and efficient. By allowing preview‑specific rendering paths through cookies and route handlers, Next.js lets both needs coexist cleanly.
That makes it one of the most practical features in the framework for editorial teams.
Related Articles

Detecting and Dealing with Website Theft. 
Building a Headless CMS‑Powered Site with Next.js. Building a Headless CMS‑Powered Site with Next.js

Creating Progressive Web Apps (PWAs) with Angular. Creating Progressive Web Apps (PWAs) with Angular

How to Find a Programmer Job. How to Find a Programmer Job

Quickselect in TypeScript: Solving 'Kth Largest Element in an Array'. Quickselect in TypeScript: Solving 'Kth Largest Element in an Array'

Using the filter() Method in JavaScript. Using the
filter()Method in JavaScript
Flexbox vs. grid. Flexbox vs.
grid
CSS visibility: Hiding Elements Without Affecting Layout. CSS
visibility: Hiding Elements Without Affecting Layout
Reduce() in JavaScript. reduce()in JavaScript
Using next/link for Client‑Side Navigation. Using
next/linkfor Client‑Side Navigation
Primitive vs. Reference Types in JavaScript. Primitive vs. Reference Types in JavaScript

Understanding the Module Pattern in JavaScript. Understanding the Module Pattern in JavaScript