# 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:` - 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: ``` 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 ` - 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: `dev@payloadcms.com` / `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 ``` 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 ` - 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: ``` test// ├── 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 ` ## 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](https://www.conventionalcommits.org/). ### PR Title Format `(): ` - 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>   <a href="https://discord.gg/payload"><img alt="Discord" src="https://img.shields.io/discord/967097582721572934?label=Discord&color=7289da&style=flat-square" /></a>   <a href="https://www.npmjs.com/package/payload"><img alt="npm" src="https://img.shields.io/npm/dw/payload?style=flat-square" /></a>   <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>   <a href="https://www.npmjs.com/package/payload"><img alt="npm" src="https://img.shields.io/npm/v/payload?style=flat-square" /></a>   <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> · <a target="_blank" href="https://payloadcms.com/community-help" rel="dofollow"><strong>Community Help</strong></a> · <a target="_blank" href="https://github.com/payloadcms/payload/discussions/1539" rel="dofollow"><strong>Roadmap</strong></a> · <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](https://payloadcms.com/docs/getting-started/installation). ```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://deploy.workers.cloudflare.com/button)](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://vercel.com/button)](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](https://github.com/payloadcms/payload/tree/main/templates/website) #### 🛍️ [Ecommerce](https://github.com/payloadcms/payload/tree/main/templates/ecommerce) 🎉 _**NEW**_ 🎉 We're constantly adding more templates to our [**Templates Directory**](https://github.com/payloadcms/payload/tree/main/templates). If you maintain your own, add the `payload-template` topic to your GitHub repo so others can discover it. **🔗 Explore more:** - [Official Templates](https://github.com/payloadcms/payload/tree/main/templates) - [Community Templates](https://github.com/topics/payload-template) ## ✨ 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](https://payloadcms.com/docs/authentication/overview) - [Versions and drafts](https://payloadcms.com/docs/versions/overview) - [Localization](https://payloadcms.com/docs/configuration/localization) - [Block-based layout builder](https://payloadcms.com/docs/fields/blocks) - [Customizable React admin](https://payloadcms.com/docs/admin/overview) - [Lexical rich text editor](https://payloadcms.com/docs/fields/rich-text) - [Conditional field logic](https://payloadcms.com/docs/fields/overview#conditional-logic) - Extremely granular [Access Control](https://payloadcms.com/docs/access-control/overview) - [Document and field-level hooks](https://payloadcms.com/docs/hooks/overview) 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](https://payloadcms.com/docs/getting-started/what-is-payload) to find in-depth documentation for everything that Payload offers. Migrating from v2 to v3? Check out the [3.0 Migration Guide](https://github.com/payloadcms/payload/blob/main/docs/migration-guide/overview.mdx) on how to do it. ## 🙋 Contributing If you want to add contributions to this repository, please follow the instructions in [contributing.md](./CONTRIBUTING.md). ## 📚 Examples The [Examples Directory](./examples) 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](./examples) - [Payload Blog](https://payloadcms.com/blog) - [Payload YouTube](https://www.youtube.com/@payloadcms) ## 🔌 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](https://github.com/orgs/payloadcms/repositories?q=topic%3Apayload-plugin) - [Community Plugins](https://github.com/topics/payload-plugin) ## 🚨 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](https://github.com/payloadcms/payload/discussions) - [GitHub Issues](https://github.com/payloadcms/payload/issues) - [Discord](https://t.co/30APlsQUPB) - [Community Help](https://payloadcms.com/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"/>