Payload CMS tutorial: build your first Payload 3 project, step by step

Idea Labz · Nov 11, 2026 · 12 min read

You’ve decided to try Payload, or you’ve just been handed a Payload project, and you want a working app with your own content in it. Payload 3 shipped on 19 November 2024, and walkthroughs written before then teach a setup that no longer exists.

As of 10 November 2026, the latest stable release of Payload is 3.93.0, published on 4 November, and Payload 4 is in beta (the 3.93.0 release notes). We scaffolded a blank project with create-payload-app 3.93.0 on 10 November 2026, and the requirements, the template list and the first step on this page come from that run.

This guide covers what you need before you start, which template to pick, six steps from an empty folder to a page that lists your content, how we start our own client projects, what to do when the first run fails, and where to learn next.

  • What you need before you start
  • Which Payload template should you start from?
  • Build your first Payload project, step by step
  • How we start a new Payload project
  • What to do when the first run fails
  • Where to learn Payload next
  • Frequently asked questions
  • What to do next

What you need before you start

You need a supported Node.js version, a package manager and a database Payload can reach.

  • Node.js 22.23.4 or later on the 22 line, or 24.22.1 or later. That’s the range in the engines field of the payload 3.93.0 package and in Payload’s installation docs. Payload’s own Get started page still lists Node.js 20.9.0+, so go by the package. Check yours with node -v.
  • pnpm 10.26 or later. Payload prefers pnpm, and the blank template’s pnpm-workspace.yaml uses the allowBuilds setting, which pnpm added in 10.26.0 on 15 December 2025. npm and Yarn 2 or later also work; Yarn 1 doesn’t.
  • A database. SQLite is the shortest path on a laptop, because the database is a single file and there’s no server to run. Postgres and MongoDB are the other two official options, and which database to choose covers the trade-offs for a project you’ll deploy.

For example, when we scaffolded the blank template on 10 November 2026 with create-payload-app 3.93.0, pnpm 9.15.0 and Node.js 22.23.0, the install stopped at “packages field missing or empty”, and our Node version sat below the floor.

Which Payload template should you start from?

Start from blank if you’re learning Payload or designing your own content model, and from website if you’re building a marketing site or a blog. create-payload-app offers five templates in its picker as of version 3.93.0, all from the templates folder in Payload’s repository.

TemplateWhat you getPick it when
blankA users collection for admin sign-in and a media collection for uploadsYou’re learning, or the content model is yours to design
websitePages, posts, categories, media and users, header and footer globals, a layout builder, drafts, live preview, SEO, search, redirects and a Next.js front endYou need a marketing site, a blog or a portfolio
ecommerceProducts with variants, carts, addresses, orders and transactions from Payload’s ecommerce plugin, plus pages, categories, media and usersYou’re building a store
with-cloudflare-d1The blank setup on Cloudflare Workers, with D1 for data and R2 for mediaYou’re deploying to Cloudflare
pluginA plugin package with a development project to test it inYou’re writing a Payload plugin

The blog template people search for is the website template. Its posts carry categories, drafts and SEO fields, and the admin has a “seed database” link that fills it with sample pages and posts. Keep in mind, seeding drops your current database first, so only run it on a new project (the website template’s README).

The ecommerce template runs on Payload’s ecommerce plugin, which is still in beta, and what the ecommerce plugin covers goes through it. The Cloudflare template deploys only on Cloudflare’s paid Workers plan and can’t resize images, because Workers don’t support sharp (the template’s README); where to host Payload compares it with the other routes. The website template’s SEO, search, redirects and form features come from Payload’s official plugins.

The repository also holds templates the picker doesn’t list, such as with-postgres and the with-vercel-* variants behind Payload’s one-click Vercel deploy. It also holds 13 examples on the 3.x branch, each a small project showing one feature, which you start with npx create-payload-app --example <name> (Payload’s examples). The localization and multi-tenant examples are the starting points for translated content and one admin serving several sites.

If you’re after a demo, there’s no public admin to log in to. The website template’s front end runs as a live demo on Vercel, and running the template locally gives you its admin. The “Schedule a Demo” button on Payload’s site books a sales call.

For example, an independent bookshop that wants its catalogue online starts on blank, because the catalogue is its content model. It’s the project for the rest of this tutorial.

Build your first Payload project, step by step

You’ll build the bookshop’s catalogue in six steps:

  1. Create the project
  2. Find your way around the project
  3. Start it and create the first admin user
  4. Add your first collection
  5. Add books in the admin panel
  6. Show the books on a page

1. Create the project

Run create-payload-app in the folder where you keep your projects:

npx create-payload-app@latest

It asks for the project name, the template, the database, the database’s connection string (with a local default you can accept) and the coding agent to install Payload’s skill for, in that order. Pick blank and SQLite for the bookshop.

The last question arrived in version 3.83.0 on 15 April 2026 (the 3.83.0 release notes). Choose Claude Code, Codex or Cursor and the CLI downloads Payload’s skill into the project and writes a CLAUDE.md or AGENTS.md at the root, so your coding assistant follows Payload’s own rules. Choose None to skip it. Payload’s agent skills covers what the skill gives an assistant.

You can answer everything up front instead:

npx create-payload-app@latest --name bookshop -t blank --db sqlite --db-accept-recommended --no-agent --use-pnpm

The CLI writes a .env file with DATABASE_URL pointing at the SQLite file and a generated PAYLOAD_SECRET, then installs the dependencies. Read the install line before you move on, because in our run the install failed and the CLI still finished with “Payload project successfully created!”

2. Find your way around the project

The blank template gives you a Next.js app with Payload inside it. Trimmed to the parts you’ll touch, our scaffold looked like this:

bookshop/
├── .env
├── docker-compose.yml
├── next.config.ts
├── package.json
└── src/
    ├── app/
    │   ├── (frontend)/
    │   │   ├── layout.tsx
    │   │   └── page.tsx
    │   └── (payload)/
    │       ├── admin/
    │       └── api/
    ├── collections/
    │   ├── Media.ts
    │   └── Users.ts
    ├── payload-types.ts
    └── payload.config.ts

payload.config.ts registers your collections, the database adapter, the rich text editor and plugins. The (payload) folder holds the admin panel and the REST and GraphQL routes, generated for you and not meant to be edited. Your own pages go in (frontend), and how Payload runs inside a Next.js app explains the two route groups. payload-types.ts holds TypeScript types generated from your config.

3. Start it and create the first admin user

If the CLI’s install failed, run pnpm install first. Then start the development server:

pnpm dev

Open http://localhost:3000/admin. With no users in the database yet, Payload sends you to its create-first-user screen at /admin/create-first-user, where you set the email and password of the first admin (Payload’s admin panel docs). After that, the dashboard lists the template’s two collections, Users and Media.

4. Add your first collection

A collection is a set of documents with the same fields, and Payload builds the admin screens, the database table and the APIs from its config. Create src/collections/Books.ts:

import type { CollectionConfig } from 'payload'

export const Books: CollectionConfig = {
  slug: 'books',
  admin: {
    useAsTitle: 'title',
  },
  access: {
    read: () => true,
    create: ({ req: { user } }) => Boolean(user),
    update: ({ req: { user } }) => Boolean(user),
    delete: ({ req: { user } }) => Boolean(user),
  },
  fields: [
    { name: 'title', type: 'text', required: true },
    { name: 'slug', type: 'text', required: true, unique: true },
    { name: 'author', type: 'text', required: true },
    { name: 'publishedOn', type: 'date' },
    {
      name: 'format',
      type: 'select',
      options: ['hardback', 'paperback', 'ebook'],
      defaultValue: 'paperback',
    },
    { name: 'cover', type: 'upload', relationTo: 'media' },
    { name: 'description', type: 'richText' },
  ],
}

Then register it in src/payload.config.ts:

import { Books } from './collections/Books'

// inside buildConfig
collections: [Users, Media, Books],

The access block is there because Payload’s default for every action is “signed-in users only”, so without a public read rule, visitors couldn’t read the catalogue through the API (Payload’s access control docs). The other three rules repeat the default, so anyone reading the file can see who may change a book.

On SQLite and Postgres, Payload pushes the new table to your database automatically in development (Payload’s migration docs). Before you deploy, you switch to migrations, and moving content and running payload migrate covers that step. Outside production, Payload also regenerates payload-types.ts when the config changes, and pnpm generate:types does it by hand.

5. Add books in the admin panel

Reload the admin and Books appears in the sidebar. The list view shows each book by its title, because of useAsTitle, and the edit view shows one input per field, with a text box for the author, a date picker, a dropdown for the format, an upload field for the cover and a rich text editor for the description.

For example, add a paperback with a cover image. The cover uploads into the Media collection, and the blank template’s Media collection asks for alt text on every image. Save, and the book is in your database.

The users collection is what lets you into the admin, because it has auth: true in its config. How Payload handles users and sign-in covers roles and access beyond this.

6. Show the books on a page

Your pages read content through Payload’s Local API, which calls the database directly from server code in the same app. Create src/app/(frontend)/books/page.tsx:

import { getPayload } from 'payload'
import config from '@payload-config'

export default async function BooksPage() {
  const payload = await getPayload({ config })
  const { docs: books } = await payload.find({
    collection: 'books',
    sort: 'title',
    limit: 50,
  })

  return (
    <main>
      <h1>Books</h1>
      <ul>
        {books.map((book) => (
          <li key={book.id}>
            {book.title} by {book.author}
          </li>
        ))}
      </ul>
    </main>
  )
}

Open http://localhost:3000/books and the list renders from your database. The same books are available over REST at /api/books, which is the route a separate front end or a mobile app would use (Payload’s REST API docs).

The Local API skips access rules by default, because overrideAccess is true on every Local API call (Payload’s Local API docs). The public read rule is what lets visitors reach /api/books. When the bookshop grows, whether to keep one app or split the site out, and how to refresh pages after an edit, are covered in Payload and Next.js.

How we start a new Payload project

For a one-off project, create-payload-app is the right start. As of October 2026, we manage 29 Payload codebases, all built on Next.js, and every client project starts as a clone of our project template (v2.3.2, 4 November 2026), never from create-payload-app or one of Payload’s templates. One setup command then creates each app’s local settings from the template’s examples, generates fresh secrets for that project, creates a local Postgres database, stamps the project with the template release it came from and links it back to the template. It finishes with a short checklist of the values a person still pastes in by hand, such as the settings for third-party accounts.

A fresh clone already has a Payload admin, two front ends that read the same content (one through GraphQL, one through REST), an Expo mobile app, and shared packages for UI, types, design tokens and an API client, and each build uses the ones it needs. In development, a seed creates the first tenant and a default user, so the admin opens with something in it. The official plugins and our own are configured. For AI-powered development, the repository carries an agent guide at the root, the project’s own architecture docs, a written, spec-driven workflow for changes, and a copy of Payload’s documentation, so assistants read the real docs. Our coding agents also load Payload’s own payload skill, the skill create-payload-app offers to install in step 1.

Adding a collection works differently from the bookshop’s too. A project’s own collections, blocks, globals, plugins, seed and theme live in a folder of their own, and the shared core is never edited in place. The build refuses a collection that leaves any access action to Payload’s default, so every collection states who can read, create, update and delete, as the bookshop’s does. A new collection ships with its database migration in the same change, and it’s scoped to its tenant automatically.

The template ships numbered releases, and a project takes one with a single command. The command merges the release, then runs the install, the type check, the build, the tests and a check that nothing outside the project’s own folder changed, stopping at the first failure. Because each project’s work lives in its own folder, a release merges cleanly, much as a WordPress child theme takes updates to its parent. If you’d rather start from a team’s template than a blank app, our Payload development work starts every project this way.

What to do when the first run fails

The failures below are listed by the message you’ll see, starting with the two our own scaffold hit.

“packages field missing or empty” during the install

Your pnpm is older than the template expects. The blank template’s workspace file uses allowBuilds, added in pnpm 10.26.0, and pnpm 9 rejects the file. Upgrade pnpm, then run pnpm install again.

Node.js below Payload’s range

Payload 3.93.0 declares ^22.23.4 || >=24.22.1 in its engines field. If node -v prints anything lower, upgrade Node before installing, even where a guide lists 20.9.0.

Error: cannot connect to Postgres or cannot connect to SQLite

Payload couldn’t open the database in DATABASE_URL. For Postgres or MongoDB, check the server is running and the connection string in .env matches it. The template’s docker-compose.yml starts the app with a MongoDB container, and a commented-out Postgres service you can switch on. For SQLite, check the file path in DATABASE_URL.

Error: missing secret key

Payload stops at startup with Error: missing secret key. A secret key is needed to secure Payload. when PAYLOAD_SECRET is empty. create-payload-app writes one for you, so this usually means the .env file wasn’t created or wasn’t loaded. Set a long random string and restart.

A Next.js version Payload doesn’t support

@payloadcms/next lists the Next.js releases it accepts as a peer dependency, so your package manager flags a version outside that range. Upgrading Next.js and Payload together covers how to read the range.

New fields missing from your types

If your editor doesn’t know a field you just added, run pnpm generate:types to rebuild payload-types.ts.

A custom admin component doesn’t show

Payload finds custom admin components through an import map it regenerates at startup. If one doesn’t appear, run pnpm payload generate:importmap and restart (Payload’s custom components docs).

Where to learn Payload next

Payload’s own material is the place to go next, because it tracks the release you’ve installed.

  • The docs. Payload’s documentation covers 3.x, with separate docs for the 4.0 beta. For AI tools, llms.txt points to a single-file version of each.
  • Guides and tutorials. Payload’s guides list 21 as of 10 November 2026, from collections and globals to rich text, blocks, the Local API, SEO and storage.
  • GitHub. The Payload repository is MIT licensed and had 45,747 stars on 10 November 2026. It holds the templates, the examples, the releases and Discussions.
  • The community. Payload’s Discord, its Community Help archive, its YouTube channel and the r/PayloadCMS subreddit.
  • Courses. Payload doesn’t offer an official course as of 10 November 2026, and a GitHub discussion asking for one has been open since March 2024. Community courses and video series exist. Check which version each teaches, because anything made before Payload 3.0 covers Payload 2 or earlier. For example, a course whose config imports buildConfig from payload/config teaches Payload 2, because Payload 3 imports it from payload.

Once the bookshop works, this order follows the questions a first project raises next:

  1. Pick the database you’ll deploy on.
  2. Set up users, roles and sign-in.
  3. Shape the admin for your editors.
  4. Add the official plugins you need.
  5. Decide where to host it.

Frequently asked questions

Is Payload CMS free to use?

Yes. Payload is open source under the MIT licence, and what Payload costs to run covers hosting and the Enterprise licence.

Does Payload have a blog template?

Yes, the website template. It ships posts with categories, pages, drafts, SEO fields, search and redirects, plus a Next.js front end.

Is there a Payload CMS demo?

The website template’s front end runs as a live demo on Vercel, but there’s no public admin to log in to. Run the website template locally to try the admin with sample content.

Is there an official Payload CMS course?

No, as of 10 November 2026. Payload’s docs, guides and examples are the official learning material.

Can I learn Payload without knowing Next.js?

Yes, for the config, which is plain TypeScript, and the admin panel, which Payload builds from it. Your pages are Next.js, so you’ll need its basics by step 6.

Can I add Payload to an existing Next.js app?

Should I start on the Payload 4 beta?

As of 10 November 2026, the beta is at 4.0.0-beta.7 on npm, and our Payload review covers what it changes and when to move.

Do I need Docker to run Payload locally?

No. SQLite needs nothing beyond the project, and the template’s Docker Compose file is there if you’d rather run the app and a database in containers. For self-hosting, running Payload in production covers whether you need Docker there.

What to do next

Check your Node.js and pnpm versions before anything else, because our own first install stopped on the pnpm version. Start on blank with SQLite to learn, build one real collection with its access rules, and read it on a page with the Local API. Move to the website template when you need a full site or blog. Then work through the Payload guide for the rest of how Payload works.

References

All links checked and active as of 10 November 2026.

READY TO MAKE A REAL CHANGE?

Let's build it together