How to Set Up Payload CMS with Next.js 16
Payload CMS is the only headless CMS that installs directly into your Next.js application — no separate server, no extra deployment, no schema drift. With Next.js 16 now the active LTS release, this guide walks you through setting up a fresh Payload + Next.js 16 project from scratch.
Prerequisites
- Node.js 20 or later
- A PostgreSQL database (local or hosted, e.g. Neon, Supabase, Railway)
- Basic familiarity with Next.js App Router
Step 1: Scaffold a New Project
The fastest way to get started is with the official create-payload-app CLI, which scaffolds a Next.js 16 app with Payload pre-configured:
npx create-payload-app@latest my-site
cd my-site
When prompted, choose the website or blank template and select PostgreSQL as your database adapter.
Step 2: Configure Your Database
Open the generated .env file and add your database connection string:
DATABASE_URI=postgresql://user:password@localhost:5432/my_payload_db
PAYLOAD_SECRET=your-super-secret-key-here
The PAYLOAD_SECRET is used to sign JWTs and encrypt sensitive data — use a long, random string in production.
Step 3: Explore the Payload Config
The heart of your Payload setup lives in src/payload.config.ts. A minimal config looks like this:
import { buildConfig } from 'payload'
import { postgresAdapter } from '@payloadcms/db-postgres'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
export default buildConfig({
secret: process.env.PAYLOAD_SECRET || '',
db: postgresAdapter({
pool: { connectionString: process.env.DATABASE_URI },
}),
editor: lexicalEditor(),
collections: [],
})
Step 4: Create Your First Collection
Collections are the building blocks of your content model. Create a Posts collection by adding a file at src/collections/Posts.ts:
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
required: true,
},
{
name: 'content',
type: 'richText',
},
{
name: 'publishedAt',
type: 'date',
},
],
}
Then register it in your payload.config.ts:
import { Posts } from './collections/Posts'
export default buildConfig({
// ...
collections: [Posts],
})
Step 5: Run Migrations and Start the Dev Server
Payload uses Drizzle ORM under the hood. Push your schema to the database and start the dev server:
npx payload migrate
npm run dev
Navigate to http://localhost:3000/admin to create your first admin user and start adding content.
Step 6: Query Content with the Local API
The real power of Payload inside Next.js is the Local API — you can query your database directly in Server Components without any HTTP round-trips:
import { getPayload } from 'payload'
import config from '@payload-config'
export default async function BlogPage() {
const payload = await getPayload({ config })
const posts = await payload.find({
collection: 'posts',
where: {
publishedAt: { less_than_equal: new Date().toISOString() },
},
sort: '-publishedAt',
limit: 10,
})
return (
<ul>
{posts.docs.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Step 7: Deploy
Because Payload runs inside your Next.js app, deployment is the same as any Next.js project. Push to Vercel, Railway, or any Node.js host. Make sure your environment variables (DATABASE_URI and PAYLOAD_SECRET) are set in your hosting dashboard.
Key Takeaway: Payload CMS eliminates the friction of managing a separate CMS server. By living inside your Next.js 16 app, you get full TypeScript types, zero-latency Local API queries, and a single deployment — making it one of the most developer-friendly CMS setups available in 2026.
Hashtags: #PayloadCMS #NextJS #WebDevelopment #HeadlessCMS #TypeScript #ReactJS #FullStack
Resources: