Preview Mode in Next.js with a Headless CMS

Hero image for Preview Mode in Next.js with a Headless CMS. Image by from nio.
Hero image for 'Preview Mode in Next.js with a Headless CMS.' Image by from nio.

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, productionready 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 requesttime 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
  • CMSgenerated 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 productionready entries.

Preview mode may read:

  • drafts
  • unpublished revisions
  • staging API responses
  • editorfacing 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 previewspecific 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.


Categories:

  1. CMS
  2. Development
  3. Front‑End Development
  4. Guides
  5. JavaScript
  6. Next.js