payload

Payload is the open-source, fullstack Next.js framework, giving you instant backend superpowers. Get a full TypeScript backend and admin panel instantly. Use Payload as a headless CMS or for building powerful applications.

44,113 stars TypeScript Markdown Skills API Spec #cms#content-management#content-management-system#express
AI Prompts & Specs

Repository: payloadcms/payload


Stars: 41874

CLAUDE.md

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) and Cursor when working with code in this repository.

Project Structure

Payload is a monorepo structured around Next.js, containing the core CMS platform, database adapters, plugins, and tooling.

Key Directories

- packages/ - All publishable packages
- packages/payload - Core Payload package containing the main CMS logic
- packages/ui - Admin UI components (React Server Components)
- packages/next - Next.js integration layer
- packages/db-* - Database adapters (MongoDB, Postgres, SQLite, Vercel Postgres, D1 SQLite)
- packages/drizzle - Drizzle ORM integration
- packages/kv-redis - Redis key-value store adapter
- packages/richtext-* - Rich text editors (Lexical, Slate)
- packages/storage-* - Storage adapters (S3, Azure, GCS, Uploadthing, Vercel Blob, R2)
- packages/email-* - Email adapters (Nodemailer, Resend)
- packages/plugin-* - Additional functionality plugins
- packages/graphql - GraphQL API layer
- packages/translations - i18n translations
- test/ - Test suites organized by feature area. Each directory contains a granular Payload config and test files
- docs/ - Documentation (deployed to payloadcms.com)
- tools/ - Monorepo tooling
- templates/ - Production-ready project templates
- examples/ - Example implementations

Architecture Notes

- Payload 3.x is built as a Next.js native CMS that installs directly in /app folder
- UI is built with React Server Components (RSC)
- Database adapters use Drizzle ORM under the hood
- Packages use TypeScript with strict mode and path mappings defined in tsconfig.base.json
- Source files are in src/, compiled outputs go to dist/
- Monorepo uses pnpm workspaces and Turbo for builds

Quick Start

1. pnpm install
2. pnpm run build:core
3. pnpm run dev (MongoDB) or pnpm run dev:postgres

Build Commands

- pnpm install - Install all dependencies
- pnpm turbo - All Turbo commands should be run from root with pnpm - not with turbo directly
- pnpm run build or pnpm run build:core - Build core packages (excludes plugins and storage adapters)
- pnpm run build:all - Build all packages
- pnpm run build:<directory_name> - Build specific package (e.g. pnpm run build:db-mongodb, pnpm run build:ui)

Development

Coding Patterns and Best Practices

- Prefer single object parameters (improves backwards-compatibility)
- Prefer types over interfaces (except when extending external types)
- Prefer functions over classes (classes only for errors/adapters)
- Prefer pure functions; when mutation is unavoidable, return the mutated object instead of void.
- Organize functions top-down: exports before helpers
- Use JSDoc for complex functions; add tags only when justified beyond type signature
- Use import type for types, regular import for values, separate statements even from same module
- Prefix booleans with is/has/can/should (e.g., isValid, hasData) for clarity
- Prefer self describing function and variable names over generic names with comments to explain their purpose
- Commenting Guidelines

- Execution flow: Skip comments when code is self-documenting. Keep for complex logic, non-obvious "why", multi-line context, or if following a documented, multi-step flow.
- Top of file/module: Use sparingly; only for non-obvious purpose/context or an overview of complex logic.
- Type definitions: Property/interface documentation is always acceptable.

- Logger Usage (payload.logger.error)
- Valid: payload.logger.error('message') or payload.logger.error({ msg: '...', err: error })
- Invalid: payload.logger.error('message', err) - don't pass error as second argument
- Use err not error, use msg not message in object form

React Component File Structure

Each React component should have its own named folder:

text
ComponentName/
β”œβ”€β”€ index.tsx # Component implementation
└── index.scss # Styles (if applicable)

- Do: Create a folder per component with index.tsx and index.scss
- Don't: Place multiple ComponentName.tsx files in a single folder with one shared .scss file
- Re-export from barrel files (index.ts) when grouping related components in a parent directory

Running Dev Server

- pnpm run dev - Start dev server with default config (test/_community/config.ts)
- pnpm run dev <directory_name> - Start dev server with specific test config (e.g. pnpm run dev fields loads test/fields/config.ts)
- pnpm run dev:postgres - Run dev server with Postgres

Development Environment

- Auto-login is enabled by default with credentials: [email protected] / test
- To disable: pass --no-auto-login flag or set PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN=false
- Default database is MongoDB (in-memory). Switch to Postgres with PAYLOAD_DATABASE=postgres
- Docker services: pnpm docker:start / pnpm docker:clean / pnpm docker:test

Playwright MCP

You should have access to the Playwright MCP server. This MCP server enables LLMs to interact with web pages through structured accessibility snapshots, bypassing the need for screenshots or visually-tuned models.

Prerequisites:

- The dev server MUST be running (pnpm run dev) before using the MCP
- First call browser_install to set up the browser if needed

Key tools (not exhaustive):

- browser_navigate - Navigate to a URL
- browser_snapshot - Get accessibility snapshot of current page
- browser_click - Click elements (requires ref from snapshot)
- browser_fill_form - Fill form fields
- browser_take_screenshot - Capture screenshot (use fullPage: true for full page)

Screenshots for visual verification:

Use browser_take_screenshot to visually verify UI state. Useful for:

- Confirming layout and styling look correct
- Checking component rendering (tags, forms, tables)
- Debugging UI issues that aren't visible in accessibility snapshots

text
browser_take_screenshot()                    # Viewport only
browser_take_screenshot({ fullPage: true }) # Full scrollable page

Screenshots are saved to .playwright-mcp/ and displayed inline.

Usage flow:

1. Ensure dev server is running on localhost:3000
2. Call browser_navigate to open a page
3. Call browser_snapshot to get element refs
4. Use refs to interact with browser_click, browser_fill_form, etc.

Testing

Writing Tests - Required Practices

Tests MUST be self-contained and clean up after themselves:

- If you create a database record in a test, you MUST delete it before the test completes
- For multiple tests with similar cleanup needs, use afterEach to centralize cleanup logic
- Track created resources (IDs, files, etc.) in a shared array within the describe block
- Do not use conditionals in tests where it can be avoided such as if else
- Do not use try {} finally {} in e2e tests; prefer Playwright cleanup hooks (afterEach, afterAll)

Example pattern:

typescript
describe('My Feature', () => {
const createdIDs: number[] = []

afterEach(async () => {
for (const id of createdIDs) {
await payload.delete({ collection: 'my-collection', id })
}
createdIDs.length = 0
})

it('should create a record', async () => {
const id = 123
createdIDs.push(id)

await payload.create({ collection: 'my-collection', data: { id, title: 'Test' } })
// assertions...
})
})

Additional test guidelines:

- Use descriptive test names starting with "should" (e.g., "should create document with custom ID")
- Add blank lines after variable declarations to improve readability
- Collection and global slugs should be kept in a shared file and re-used i.e. on relationship fields relationTo: collectionSlug
- One test should verify one behavior - keep tests focused
- When adding a new collection for testing, add it to both collections/ directory and the config file import statements

How to run tests

- pnpm run test - Run all tests (integration + components + e2e)
- pnpm run test:int - Integration tests (MongoDB, recommended)
- pnpm run test:int <dir> - Specific test suite (e.g. fields)
- pnpm run test:int:postgres|sqlite - Integration tests with other databases
- pnpm run test:e2e - Playwright tests (add :headed or :debug suffix)
- pnpm run test:unit|components|types - Other test suites

Test Structure

Each test directory in test/ follows this pattern:

text
test/<feature-name>/
β”œβ”€β”€ config.ts # Lightweight Payload config for testing
β”œβ”€β”€ int.spec.ts # Integration tests (Vitest)
β”œβ”€β”€ e2e.spec.ts # End-to-end tests (Playwright)
└── payload-types.ts # Generated types

Generate types for a test directory: pnpm run dev:generate-types <directory_name>

Linting & Formatting

- pnpm run lint - Run linter across all packages
- pnpm run lint:fix - Fix linting issues

Internationalization

- Translation files are in packages/translations/src/languages/
- Add new strings to English locale first, then translate to other languages
- Run pnpm run translateNewKeys to auto-translate new keys (requires OPENAI_KEY in .env)
- Lexical translations: cd packages/richtext-lexical && pnpm run translateNewKeys

Commit & PR Guidelines

This repository follows Conventional Commits.

PR Title Format

<type>(<scope>): <title>

- Title must start with lowercase letter
- Types: build, chore, ci, docs, examples, feat, fix, perf, refactor, revert, style, templates, test
- Prefer feat for new features, fix for bug fixes
- Scopes match package names: db-, richtext-, storage-, plugin-, ui, next, graphql, translations, etc.
- Choose most relevant scope if multiple packages modified, or omit scope entirely

Examples:

- feat(db-mongodb): add support for transactions
- feat(richtext-lexical): add options to hide block handles
- fix(ui): json field type ignoring editorOptions
- feat: add new collection functionality

Commit Guidelines

- First commit of branch should follow PR title format
- Subsequent commits should use chore without scope unless specific package is being modified
- All commits in a PR are squashed on merge using PR title as commit message

Additional Resources

- LLMS.txt: <https://payloadcms.com/llms.txt>
- LLMS-FULL.txt: <https://payloadcms.com/llms-full.txt>
- Node version: ^18.20.2 || >=20.9.0
- pnpm version: ^10.27.0


README.md

<a href="https://payloadcms.com"><img width="100%" src="https://l4wlsi8vxy8hre4v.public.blob.vercel-storage.com/github-banner-new-logo.jpg" alt="Payload headless CMS Admin panel built with React" /></a>
<br />
<br />

<p align="left">
<a href="https://github.com/payloadcms/payload/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/payloadcms/payload/main.yml?style=flat-square"></a>
&nbsp;
<a href="https://discord.gg/payload"><img alt="Discord" src="https://img.shields.io/discord/967097582721572934?label=Discord&color=7289da&style=flat-square" /></a>
&nbsp;
<a href="https://www.npmjs.com/package/payload"><img alt="npm" src="https://img.shields.io/npm/dw/payload?style=flat-square" /></a>
&nbsp;
<a href="https://github.com/payloadcms/payload/graphs/contributors"><img alt="npm" src="https://img.shields.io/github/contributors-anon/payloadcms/payload?color=yellow&style=flat-square" /></a>
&nbsp;
<a href="https://www.npmjs.com/package/payload"><img alt="npm" src="https://img.shields.io/npm/v/payload?style=flat-square" /></a>
&nbsp;
<a href="https://twitter.com/payloadcms"><img src="https://img.shields.io/badge/follow-payloadcms-1DA1F2?logo=twitter&style=flat-square" alt="Payload Twitter" /></a>
</p>
<hr/>
<h4>
<a target="_blank" href="https://payloadcms.com/docs/getting-started/what-is-payload" rel="dofollow"><strong>Explore the Docs</strong></a>&nbsp;Β·&nbsp;<a target="_blank" href="https://payloadcms.com/community-help" rel="dofollow"><strong>Community Help</strong></a>&nbsp;Β·&nbsp;<a target="_blank" href="https://github.com/payloadcms/payload/discussions/1539" rel="dofollow"><strong>Roadmap</strong></a>&nbsp;Β·&nbsp;<a target="_blank" href="https://www.g2.com/products/payload-cms/reviews#reviews" rel="dofollow"><strong>View G2 Reviews</strong></a>
</h4>
<hr/>

IMPORTANT

Star this repo or keep an eye on it to follow along.

Payload is the first-ever Next.js native CMS that can install directly in your existing /app folder. It's the start of a new era for headless CMS.

<h3>Benefits over a regular CMS</h3>
<ul>
<li>It's both an app framework & headless CMS</li>
<li>Deploy anywhere, including serverless on Vercel for free</li>
<li>Combine your front+backend in the same <code>/app</code> folder if you want</li>
<li>Don't sign up for yet another SaaS - Payload is open source</li>
<li>Query your database in React Server Components</li>
<li>Both admin and backend are 100% extensible</li>
<li>No vendor lock-in</li>
<li>Never touch ancient WP code again</li>
<li>Build faster, never hit a roadblock</li>
</ul>

Quickstart

Before beginning to work with Payload, make sure you have all of the required software.

text
pnpx create-payload-app@latest

If you're new to Payload, you should start with the website template (pnpx create-payload-app@latest -t website). It shows how to do _everything_ - including custom Rich Text blocks, on-demand revalidation, live preview, and more. It comes with a frontend built with Tailwind all in one /app folder.

One-click deployment options

You can deploy Payload serverlessly in one-click via Vercel and Cloudflareβ€”giving everything you need without the hassle of the plumbing.

Deploy on Cloudflare

Fully self-contained β€” one click to deploy Payload with Workers, R2 for uploads, and D1 for a globally replicated database.

![Deploy to Cloudflare](https://dub.sh/payload-cloudflare)

Deploy on Vercel

All-in-one on Vercel β€” one click to deploy Payload with a Next.js front end, Neon database, and Vercel Blob for media storage.

![Deploy with Vercel](https://dub.sh/payload-vercel)

One-click templates

Jumpstart your next project with a ready-to-go template. These are production-ready, end-to-end solutions designed to get you to market fast. Build any kind of website, ecommerce store, blog, or portfolio β€” complete with a modern front end built using React Server Components and Tailwind.

#### 🌐 Website

#### πŸ›οΈ Ecommerce πŸŽ‰ _NEW_ πŸŽ‰

We're constantly adding more templates to our Templates Directory.
If you maintain your own, add the payload-template topic to your GitHub repo so others can discover it.

πŸ”— Explore more:

- Official Templates
- Community Templates

✨ Payload Features

- Completely free and open-source
- Next.js native, built to run inside _your_ /app folder
- Use server components to extend Payload UI
- Query your database directly in server components, no need for REST / GraphQL
- Fully TypeScript with automatic types for your data
- Auth out of the box
- Versions and drafts
- Localization
- Block-based layout builder
- Customizable React admin
- Lexical rich text editor
- Conditional field logic
- Extremely granular Access Control
- Document and field-level hooks for every action Payload provides
- Intensely fast API
- Highly secure thanks to HTTP-only cookies, CSRF protection, and more

<a target="_blank" href="https://github.com/payloadcms/payload/discussions"><strong>Request Feature</strong></a>

πŸ—’οΈ Documentation

Check out the Payload website to find in-depth documentation for everything that Payload offers.

Migrating from v2 to v3? Check out the 3.0 Migration Guide on how to do it.

πŸ™‹ Contributing

If you want to add contributions to this repository, please follow the instructions in contributing.md.

πŸ“š Examples

The Examples Directory is a great resource for learning how to setup Payload in a variety of different ways, but you can also find great examples in our blog and throughout our social media.

If you'd like to run the examples, you can use create-payload-app to create a project from one:

sh
npx create-payload-app --example example_name

You can see more examples at:

- Examples Directory
- Payload Blog
- Payload YouTube

πŸ”Œ Plugins

Payload is highly extensible and allows you to install or distribute plugins that add or remove functionality. There are both officially-supported and community-supported plugins available. If you maintain your own plugin, consider adding the payload-plugin topic to your GitHub repository for others to find.

- Official Plugins
- Community Plugins

🚨 Need help?

There are lots of good conversations and resources in our Github Discussions board and our Discord Server. If you're struggling with something, chances are, someone's already solved what you're up against. :point_down:

- GitHub Discussions
- GitHub Issues
- Discord
- Community Help

⭐ Like what we're doing? Give us a star

πŸ‘ Thanks to all our contributors

<img align="left" src="https://contributors-img.web.app/image?repo=payloadcms/payload"/>