The Payload Live Preview Example demonstrates how to implement Live Preview in Payload. With Live Preview you can render your front-end application directly within the Admin panel. As you type, your changes take effect in real-time. No need to save a draft or publish your changes.
IMPORTANT—This example includes a fully integrated Next.js App Router front-end that runs on the same server as Payload.
- Run the following command to create a project from the example:
npx create-payload-app --example live-preview
-
cp .env.example .env
to copy the example environment variables -
pnpm dev
,yarn dev
ornpm run dev
to start the server- Press
y
when prompted to seed the database
- Press
-
open http://localhost:3000
to access the home page -
open http://localhost:3000/admin
to access the admin panel- Login with email
[email protected]
and passworddemo
- Login with email
That's it! Changes made in ./src
will be reflected in your app. See the Development section for more details.
Live Preview works by rendering an iframe on the page that loads your front-end application. The Admin panel communicates with your app through window.postMessage
events. These events are emitted every time a change is made to the document. Your app then listens for these events and re-renders itself with the data it receives.
See the Collections docs for details on how to extend any of this functionality.
-
The
users
collection is auth-enabled which provides access to the admin panel. This is where your front-end application will be rendered with live page data. See Pages for more details.// ./src/collections/Index.ts { // ... auth: true }
For additional help with authentication, see the Authentication docs or the official Auth Example.
-
The
pages
collection has Live Preview enabled through theadmin.livePreview
property of thepages
collection config:// ./src/collections/Pages.ts { // ... admin: { livePreview: { url: ({ data }) => `${process.env.PAYLOAD_URL}/${data.slug}` } } }
For more details on how to extend this functionality, see the Live Preview docs.
While using Live Preview, the Admin panel emits a new window.postMessage
event every time a change is made to the document. Your front-end application can listen for these events and re-render accordingly.
There are two ways to use Live Preview in your own application depending on whether your front-end framework supports server components:
We suggest using server-side Live Preview if your framework supports it, it is both simpler to setup and more performant to run than the client-side alternative.Server-side Live Preview is only for front-end frameworks that support the concept of Server Components, i.e. React Server Components. If your front-end application is built with a client-side framework like the Next.js Pages Router, React Router, Vue 3, etc., see client-side Live Preview.
Server-side Live Preview works by making a roundtrip to the server every time your document is saved, i.e. draft save, autosave, or publish. While using Live Preview, the Admin panel emits a new window.postMessage
event which your front-end application can use to invoke this process. In Next.js, this means simply calling router.refresh()
which will hydrate the HTML using new data straight from the Local API.
If your server-side front-end application is built with React, you can use the RefreshRouteOnChange
function that Payload provides. In the future, all other major frameworks like Vue and Svelte will be officially supported. If you are using any of these frameworks today, you can still integrate with Live Preview yourself using the underlying tooling that Payload provides. See building your own router refresh component for more information.
If your front-end application is built with server-side React, i.e. Next.js App Router, you can use the RefreshRouteOnSave
component that Payload provides and thread it your framework's refresh function.
First, install the @payloadcms/live-preview-react
package:
npm install @payloadcms/live-preview-react
Then, render RefreshRouteOnSave
anywhere in your page.tsx
. Here's an example:
page.tsx
:
import { RefreshRouteOnSave } from './RefreshRouteOnSave.tsx'
import { getPayload } from 'payload'
import config from '../payload.config'
export default async function Page() {
const payload = await getPayload({ config })
const page = await payload.find({
collection: 'pages',
draft: true,
})
return (
<Fragment>
<RefreshRouteOnSave />
<h1>{page.title}</h1>
</Fragment>
)
}
RefreshRouteOnSave.tsx
:
'use client'
import { RefreshRouteOnSave as PayloadLivePreview } from '@payloadcms/live-preview-react'
import { useRouter } from 'next/navigation.js'
import React from 'react'
export const RefreshRouteOnSave: React.FC = () => {
const router = useRouter()
return <PayloadLivePreview refresh={router.refresh} serverURL={process.env.PAYLOAD_SERVER_URL} />
}
For more details on how to setup server-side Live Preview, see the server-side Live Preview docs.
If your front-end application is supports Server Components like the Next.js App Router, etc., we suggest setting up server-side Live Preview.
If your front-end application is built with client-side React such as Next.js Pages Router, React Router, etc., use the useLivePreview
React hook that Payload provides.
First, install the @payloadcms/live-preview-react
package:
npm install @payloadcms/live-preview-react
Then, use the useLivePreview
hook in your React component:
'use client'
import { useLivePreview } from '@payloadcms/live-preview-react'
import { Page as PageType } from '@/payload-types'
// Fetch the page in a server component, pass it to the client component, then thread it through the hook
// The hook will take over from there and keep the preview in sync with the changes you make
// The `data` property will contain the live data of the document
export const PageClient: React.FC<{
page: {
title: string
}
}> = ({ page: initialPage }) => {
const { data } = useLivePreview<PageType>({
initialData: initialPage,
serverURL: PAYLOAD_SERVER_URL,
depth: 2, // Ensure that the depth matches the request for `initialPage`
})
return <h1>{data.title}</h1>
}
In the future, all other major frameworks like Vue, Svelte, etc will be officially supported. If you are using any of these framework today, you can still integrate with Live Preview yourself using the tooling that Payload provides.
First, install the @payloadcms/live-preview
package:
npm install @payloadcms/live-preview
Then, build your own hook:
import { subscribe, unsubscribe } from '@payloadcms/live-preview'
// Build your own hook to subscribe to the live preview events
// This function will handle everything for you like
// 1. subscribing to `window.postMessage` events
// 2. merging initial page data with incoming form state
// 3. populating relationships and uploads
See building your own Live Preview hook for more details.
For more details on how to setup client-side Live Preview, see the client-side Live Preview docs.
To spin up this example locally, follow the Quick Start.
On boot, a seed script is included to scaffold a basic database for you to use as an example. You can remove pnpm seed
from the dev
script in the package.json
to prevent this behavior. You can also freshly seed your project at any time by running pnpm seed
. This seed creates a user with email [email protected]
and password demo
along with a home page and an example page with two versions, one published and the other draft.
NOTICE: seeding the database is destructive because it drops your current database to populate a fresh one from the seed template. Only run this command if you are starting a new project or can afford to lose your current data.
To run Payload in production, you need to build and serve the Admin panel. To do so, follow these steps:
- Invoke the
next build
script by runningpnpm build
ornpm run build
in your project root. This creates a.next
directory with a production-ready admin bundle. - Finally run
pnpm start
ornpm run start
to run Node in production and serve Payload from the.build
directory.
The easiest way to deploy your project is to use Payload Cloud, a one-click hosting solution to deploy production-ready instances of your Payload apps directly from your GitHub repo. You can also choose to self-host your app, check out the Deployment docs for more details.
If you have any issues or questions, reach out to us on Discord or start a GitHub discussion.