Skip to main content

payload

Use when working with Payload projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.

Quellinformationen

Repository
payloadcms/payload
Letzte Quellaktivität
15. Oktober 2026 um 23:24
Erkannte Sprache von SKILL.md
Englisch
Sterne
45.280
Forks
4.298

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
12 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
payload
description
Use when working with Payload projects (payload.config.ts, collections, fields, hooks, access control, Payload API). Use when debugging validation errors, security issues, relationship queries, transactions, or hook behavior.
# Payload Application Development Payload is a Next.js native CMS with TypeScript-first architecture, providing admin panel, database management, REST/GraphQL APIs, authentication, and file storage. ## Quick Reference | Task | Solution | Details | | ------------------------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | Auto-generate slugs | `{ type: 'slug', useAsSlug: 'title' }` | [FIELDS.md#slug-field](reference/FIELDS.md#slug-field) | | Restrict content by user | Access control with query | [ACCESS-CONTROL.md#row-level-security-with-complex-queries](reference/ACCESS-CONTROL.md#row-level-security-with-complex-queries) | | Local API user ops | `user` + `overrideAccess: false` | [QUERIES.md#access-control-in-local-api](reference/QUERIES.md#access-control-in-local-api) | | Draft/publish workflow | `versions: { drafts: true }` | [COLLECTIONS.md#versioning--drafts](reference/COLLECTIONS.md#versioning--drafts) | | Computed fields | `virtual: true` with **field-level** `hooks.afterRead` returning the value | [FIELDS.md#virtual-fields](reference/FIELDS.md#virtual-fields) | | Document titles | Stored top-level field in `admin.useAsTitle` | [COLLECTIONS.md#useastitle](reference/COLLECTIONS.md#useastitle) | | Conditional fields | `admin.condition` | [FIELDS.md#conditional-fields](reference/FIELDS.md#conditional-fields) | | Custom field validation | `validate` function | [FIELDS.md#validation](reference/FIELDS.md#validation) | | Filter relationship list | `filterOptions` on field | [FIELDS.md#relationship](reference/FIELDS.md#relationship) | | Select specific fields | `select` parameter | [QUERIES.md#field-selection](reference/QUERIES.md#field-selection) | | Auto-set author/dates | beforeChange hook | [HOOKS.md#collection-hooks](reference/HOOKS.md#collection-hooks) | | Prevent hook loops | `req.context` check | [HOOKS.md#context](reference/HOOKS.md#context) | | Cascading deletes | beforeDelete hook | [HOOKS.md#collection-hooks](reference/HOOKS.md#collection-hooks) | | Geospatial queries | `point` field with `near`/`within` | [FIELDS.md#point-geolocation](reference/FIELDS.md#point-geolocation) | | Reverse relationships | `join` field type | [FIELDS.md#join-fields](reference/FIELDS.md#join-fields) | | Next.js revalidation | Context control in afterChange | [HOOKS.md#nextjs-revalidation-with-context-control](reference/HOOKS.md#nextjs-revalidation-with-context-control) | | Query by relationship | Nested property syntax | [QUERIES.md#nested-properties](reference/QUERIES.md#nested-properties) | | Complex queries | AND/OR logic | [QUERIES.md#andor-logic](reference/QUERIES.md#andor-logic) | | Transactions | Pass `req` to operations | [ADAPTERS.md#threading-req-through-operations](reference/ADAPTERS.md#threading-req-through-operations) | | Background jobs | Jobs queue with tasks | [ADVANCED.md#jobs-queue](reference/ADVANCED.md#jobs-queue) | | Custom API routes | Collection custom endpoints | [ADVANCED.md#custom-endpoints](reference/ADVANCED.md#custom-endpoints) | | Cloud storage | Storage adapter plugins | [ADAPTERS.md#storage-adapters](reference/ADAPTERS.md#storage-adapters) | | Multi-language | `localization` config + `localized: true` | [ADVANCED.md#localization](reference/ADVANCED.md#localization) | | Create plugin | `(options) => (config) => Config` | [PLUGIN-DEVELOPMENT.md#plugin-architecture](reference/PLUGIN-DEVELOPMENT.md#plugin-architecture) | | Plugin package setup | Package structure with SWC | [PLUGIN-DEVELOPMENT.md#plugin-package-structure](reference/PLUGIN-DEVELOPMENT.md#plugin-package-structure) | | Add fields to collection | Map collections, spread fields | [PLUGIN-DEVELOPMENT.md#adding-fields-to-collections](reference/PLUGIN-DEVELOPMENT.md#adding-fields-to-collections) | | Plugin hooks | Preserve existing hooks in array | [PLUGIN-DEVELOPMENT.md#adding-hooks](reference/PLUGIN-DEVELOPMENT.md#adding-hooks) | | Check field type | Type guard functions | [FIELD-TYPE-GUARDS.md](reference/FIELD-TYPE-GUARDS.md) | ## Quick Start ```bash npx create-payload-app@latest my-app cd my-app pnpm dev ``` ### Minimal Config ```ts 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, }), }) ``` ## Essential Patterns ### Defaults & Conventions Apply these defaults when modeling content unless there's a clear reason not to: - **Enable drafts/versions by default:** `versions: { drafts: true }`. This is the recommended starting point for any content collection. It auto-injects a `_status` field (`draft` / `published` / `changed`) — **don't add your own `status` field**, it's redundant. Only skip versions for collections that have no publish/draft lifecycle (e.g. internal join tables, settings). - **Use the native `slug` field type for all slugs** instead of hand-rolling `{ name: 'slug', type: 'text', unique: true }`. It auto-generates the slug from a source field, adds a regenerate toggle, and defaults to `required`, `unique`, `index`, and `position: 'sidebar'`. `useAsSlug` is **required** — name the source field to generate from: `{ name: 'slug', type: 'slug', useAsSlug: 'title' }`. - **`position: 'sidebar'` is for short, at-a-glance fields** — status, category, author, publish date. Avoid it for long fields that need horizontal space to be usable (description, rich text content, long text). Those belong in the main document area. - **Use a stored top-level field for `admin.useAsTitle`.** Never set `admin.useAsTitle` to a computed field configured with `virtual: true`; these fields are not queryable and Payload rejects the configuration. A relationship-path virtual such as `virtual: 'author.name'` is supported, but use it only when the title must come from a related document. ### Basic Collection ```ts import type { CollectionConfig } from 'payload' export const Posts: CollectionConfig = { slug: 'posts', admin: { useAsTitle: 'title', // _status (from versions.drafts) shows the draft/published state — no custom status field needed defaultColumns: ['title', 'author', '_status', 'createdAt'], }, versions: { drafts: true, }, fields: [ { name: 'title', type: 'text', required: true }, { name: 'slug', type: 'slug', useAsSlug: 'title' }, // auto-generates from `title`, unique + indexed, sidebar position { name: 'content', type: 'richText' }, // long field — stays in the main area, not the sidebar // short, at-a-glance field — good sidebar candidate { name: 'author', type: 'relationship', relationTo: 'users', admin: { position: 'sidebar' } }, ], timestamps: true, } ``` For more collection patterns (auth, upload, drafts, live preview), see [COLLECTIONS.md](reference/COLLECTIONS.md). ### Common Fields ```ts // Text field { name: 'title', type: 'text', required: true } // Relationship { name: 'author', type: 'relationship', relationTo: 'users', required: true } // Rich text { name: 'content', type: 'richText', required: true } // Slug — use the native field type instead of a hand-rolled text field { name: 'slug', type: 'slug', useAsSlug: 'title' } // Select (for genuine taxonomy — NOT publish state; use versions.drafts + _status for that) { name: 'category', type: 'select', options: ['news', 'tutorial', 'opinion'] } // Upload { name: 'image', type: 'upload', relationTo: 'media' } ``` For all field types (array, blocks, point, join, virtual, conditional, etc.), see [FIELDS.md](reference/FIELDS.md). ### Hook Example Hooks live at one of two levels and they are not interchangeable. **Collection hooks** receive `{ doc, data, req, operation, ... }` and act on the whole document. **Field hooks** live inside an individual field's `hooks` object, receive `{ value, siblingData, ... }`, and **return the new value** for that field. Computed/virtual fields, per-field formatters, and per-field access masking are field hooks; cross-field business logic is a collection hook. ```ts // Collection-level: business logic across the document export const Posts: CollectionConfig = { slug: 'posts', hooks: { beforeChange: [ async ({ data, operation }) => { if (operation === 'create') { data.slug = slugify(data.title) } return data }, ], }, fields: [{ name: 'title', type: 'text' }], } // Field-level: compute / format a single field's value (virtual fields use this) export const Users: CollectionConfig = { slug: 'users', fields: [ { name: 'firstName', type: 'text' }, { name: 'lastName', type: 'text' }, { name: 'fullName', type: 'text', virtual: true, hooks: { afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], }, }, ], } ``` When asked to "compute a field" or "populate a field's value in a hook", use a **field-level** hook on that field — never a collection-level `afterRead` that mutates `doc`. For all hook patterns, see [HOOKS.md](reference/HOOKS.md). For access control, see [ACCESS-CONTROL.md](reference/ACCESS-CONTROL.md). ### Access Control with Type Safety ```ts import type { Access } from 'payload' import type { User } from '@/payload-types' // Type-safe access control export const adminOnly: Access = ({ req }) => { const user = req.user as User return user?.roles?.includes('admin') || false } // Row-level access control export const ownPostsOnly: Access = ({ req }) => { const user = req.user as User if (!user) return false if (user.roles?.includes('admin')) return true return { author: { equals: user.id }, } } ``` ### Query Example ```ts // Local API const posts = await payload.find({ collection: 'posts', overrideAccess: true, where: { status: { equals: 'published' }, 'author.name': { contains: 'john' }, }, depth: 2, limit: 10, sort: '-createdAt', }) // Query with populated relationships const post = await payload.findByID({ collection: 'posts', overrideAccess: true, id: '123', depth: 2, // Populates relationships (default is 2) }) // Returns: { author: { id: "user123", name: "John" } } // Without depth, relationships return IDs only const post = await payload.findByID({
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen