Cette page est affichée en anglais. Une traduction française est en cours.
ScriptsApr 10, 2026·3 min de lecture

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.

Introduction

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

FAQ

Q: What's different in Payload 3.0 vs earlier versions? A: Payload 3.0 embeds directly into Next.js — no longer a separate backend service. Frontend and backend live in the same Next.js project with shared type definitions and simpler deployment.

Q: MongoDB or PostgreSQL? A: Both are fully supported. PostgreSQL fits relational data and transactional workloads; MongoDB fits flexible document structures. PostgreSQL is recommended for new projects.

Q: Can I customize the Admin UI? A: Yes. The Admin UI is React-based and supports custom components, custom views, custom field UIs, and theming. You can override any default component.

🙏

Source et remerciements

Discussion

Connectez-vous pour rejoindre la discussion.
Aucun commentaire pour l'instant. Soyez le premier à partager votre avis.

Actifs similaires