gbmake-payload/.cursor/rules/payload-overview.md

4.2 KiB

title description tags
Payload CMS Overview Core principles and quick reference for Payload CMS development
payload
overview
quickstart

Payload CMS Development Rules

You are an expert Payload CMS developer. When working with Payload projects, follow these rules:

Core Principles

  1. TypeScript-First: Always use TypeScript with proper types from Payload
  2. Security-Critical: Follow all security patterns, especially access control
  3. Type Generation: Run generate:types script after schema changes
  4. Transaction Safety: Always pass req to nested operations in hooks
  5. Access Control: Understand Local API bypasses access control by default

Project Structure

src/
├── app/
│   ├── (frontend)/          # Frontend routes
│   └── (payload)/           # Payload admin routes
├── collections/             # Collection configs
├── globals/                 # Global configs
├── components/              # Custom React components
├── hooks/                   # Hook functions
├── access/                  # Access control functions
└── payload.config.ts        # Main config

Minimal Config Pattern

import { buildConfig } from 'payload'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import path from 'path'
import { fileURLToPath } from 'url'

const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

export default buildConfig({
  admin: {
    user: 'users',
    importMap: {
      baseDir: path.resolve(dirname),
    },
  },
  collections: [Users, Media],
  editor: lexicalEditor(),
  secret: process.env.PAYLOAD_SECRET,
  typescript: {
    outputFile: path.resolve(dirname, 'payload-types.ts'),
  },
  db: mongooseAdapter({
    url: process.env.DATABASE_URL,
  }),
})

Getting Payload Instance

// In API routes (Next.js)
import { getPayload } from 'payload'
import config from '@payload-config'

export async function GET() {
  const payload = await getPayload({ config })

  const posts = await payload.find({
    collection: 'posts',
  })

  return Response.json(posts)
}

// In Server Components
import { getPayload } from 'payload'
import config from '@payload-config'

export default async function Page() {
  const payload = await getPayload({ config })
  const { docs } = await payload.find({ collection: 'posts' })

  return <div>{docs.map(post => <h1 key={post.id}>{post.title}</h1>)}</div>
}

Quick Reference

Task Solution
Auto-generate slugs slugField()
Restrict by user Access control with query
Local API user ops user + overrideAccess: false
Draft/publish versions: { drafts: true }
Computed fields virtual: true with afterRead
Conditional fields admin.condition
Custom validation validate function
Filter relationships filterOptions on field
Select fields select parameter
Auto-set dates beforeChange hook
Prevent loops req.context check
Cascading deletes beforeDelete hook
Geospatial queries point field with near/within
Reverse relationships join field type
Query relationships Nested property syntax
Complex queries AND/OR logic
Transactions Pass req to operations
Background jobs Jobs queue with tasks
Custom routes Collection custom endpoints
Cloud storage Storage adapter plugins
Multi-language localization + localized: true

Resources