ScriptsApr 10, 2026·1 min read

Payload CMS — Open Source Fullstack Next.js Headless CMS

Payload is the open-source headless CMS and app framework built on Next.js. TypeScript-first, code-configured, with instant admin panel, auth, and file uploads.

SC
Script Depot · Community
Quick Use

Use it first, then decide how deep to go

This block should tell both the user and the agent what to copy, install, and apply first.

npx create-payload-app@latest my-project
cd my-project
npm run dev

Open http://localhost:3000/admin — create your first admin user and start building.

Intro

Payload is an open-source, fullstack Next.js framework that gives you an instant backend with a headless CMS, admin panel, authentication, file uploads, and more — all configured in TypeScript code. Unlike traditional CMS platforms that are GUI-configured, Payload uses a code-first approach where your content schema IS your source of truth.

With 41.7K+ GitHub stars and MIT license, Payload has become one of the fastest-growing headless CMS solutions. Version 3.0 is built directly into Next.js, eliminating the traditional backend/frontend separation.

What Payload Does

Payload provides a complete backend toolkit:

  • Headless CMS: Define content types in TypeScript, get a full admin UI and API automatically
  • Authentication: Built-in auth with email/password, magic links, OAuth, and RBAC
  • Admin Panel: Auto-generated React admin interface with custom components support
  • File Uploads: Built-in media management with image resizing and cloud storage
  • Access Control: Field-level, collection-level, and document-level permissions
  • Hooks: Before/after hooks on all CRUD operations for custom business logic
  • Localization: Multi-language content with field-level translations
  • Versions & Drafts: Full version history with draft/publish workflow

Architecture (v3 — Next.js Native)

┌─────────────────────────────────────┐
│           Next.js App               │
│  ┌─────────┐  ┌──────────────────┐  │
│  │ Your    │  │  Payload Admin   │  │
│  │ Frontend│  │  (/admin)        │  │
│  │ Pages   │  │  React UI        │  │
│  └────┬────┘  └────────┬─────────┘  │
│       │                │            │
│  ┌────┴────────────────┴─────────┐  │
│  │     Payload Core Engine       │  │
│  │  Collections, Globals, Auth   │  │
│  │  Hooks, Access Control        │  │
│  └───────────────┬───────────────┘  │
└──────────────────┼──────────────────┘
                   │
            ┌──────┴───────┐
            │  MongoDB /   │
            │  PostgreSQL  │
            └──────────────┘

Getting Started

Create a Project

npx create-payload-app@latest my-app
# Choose: Next.js template
# Choose: MongoDB or PostgreSQL
# Choose: Blank or with sample data

Define a Collection

// collections/Posts.ts
import type { CollectionConfig } from 'payload';

export const Posts: CollectionConfig = {
  slug: 'posts',
  admin: {
    useAsTitle: 'title',
  },
  access: {
    read: () => true,
    create: ({ req: { user } }) => Boolean(user),
    update: ({ req: { user } }) => Boolean(user),
    delete: ({ req: { user } }) => user?.role === 'admin',
  },
  fields: [
    {
      name: 'title',
      type: 'text',
      required: true,
    },
    {
      name: 'content',
      type: 'richText',
    },
    {
      name: 'author',
      type: 'relationship',
      relationTo: 'users',
    },
    {
      name: 'status',
      type: 'select',
      options: ['draft', 'published'],
      defaultValue: 'draft',
    },
    {
      name: 'publishedDate',
      type: 'date',
    },
    {
      name: 'featuredImage',
      type: 'upload',
      relationTo: 'media',
    },
  ],
};

Payload Config

// payload.config.ts
import { buildConfig } from 'payload';
import { mongooseAdapter } from '@payloadcms/db-mongodb';
import { slateEditor } from '@payloadcms/richtext-slate';
import { Posts } from './collections/Posts';
import { Users } from './collections/Users';
import { Media } from './collections/Media';

export default buildConfig({
  collections: [Posts, Users, Media],
  editor: slateEditor({}),
  db: mongooseAdapter({
    url: process.env.DATABASE_URI || '',
  }),
  admin: {
    user: Users.slug,
  },
});

Query Data in Your App

// app/posts/page.tsx
import { getPayload } from 'payload';
import configPromise from '@payload-config';

export default async function PostsPage() {
  const payload = await getPayload({ config: configPromise });

  const posts = await payload.find({
    collection: 'posts',
    where: { status: { equals: 'published' } },
    sort: '-publishedDate',
    limit: 10,
  });

  return (
    <div>
      {posts.docs.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
        </article>
      ))}
    </div>
  );
}

Payload vs Alternatives

Feature Payload Strapi Directus Sanity
Open Source Yes (MIT) Yes Yes (BSL) No
Config approach Code (TypeScript) GUI + code GUI Code (GROQ)
Framework Next.js native Standalone Standalone Standalone
TypeScript First-class Optional N/A First-class
Database MongoDB/Postgres SQLite/MySQL/Postgres Any SQL Hosted
Admin UI Auto-generated Auto-generated Auto-generated Hosted Studio

常见问题

Q: Payload 3.0 和之前版本有什么区别? A: Payload 3.0 直接嵌入 Next.js,不再是独立的后端服务。前端和后端在同一个 Next.js 项目中,共享类型定义,部署更简单。

Q: MongoDB 还是 PostgreSQL? A: 两者都完全支持。PostgreSQL 适合需要关系型数据和事务的场景,MongoDB 适合灵活的文档结构。新项目推荐 PostgreSQL。

Q: 可以自定义 Admin UI 吗? A: 可以。Payload 的 Admin UI 基于 React,支持自定义组件、自定义视图、自定义字段 UI、和主题定制。你可以覆盖任何默认组件。

来源与致谢

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets