Skip to main content

globals

This skill should be used when the user asks to "create a Payload global", "add site settings", "build a header/footer global", "define a GlobalConfig", "set global access control", "add hooks to a global", "fetch a global with the Local API", or needs to model any single-instance configuration (nav, homepage, announcement banner) in PayloadCMS v3.

Source facts

Repository
Agents-Store/opencode-plugins
Last source activity
August 18, 2026 at 12:05
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
globals
description
This skill should be used when the user asks to "create a Payload global", "add site settings", "build a header/footer global", "define a GlobalConfig", "set global access control", "add hooks to a global", "fetch a global with the Local API", or needs to model any single-instance configuration (nav, homepage, announcement banner) in PayloadCMS v3.
# PayloadCMS — Globals A Global is a **singleton** document — exactly one instance exists for its slug. Where a collection holds many rows, a Global holds one: site settings, the header, the footer, primary navigation, a homepage config, or an announcement banner. Like a collection, each Global is a typed document, a REST/GraphQL endpoint, an admin panel page, and an auto-generated TypeScript type — all from one config object. ## Global vs. single-doc collection Reach for a **Global** when there is conceptually one and only one record, edited in place with no list view and no create/delete. Reach for a **collection** when you have (or might have) more than one — even "one per locale" or "one per tenant" is still a collection. If two Globals would share an identical field structure, model them as one collection instead. ## Minimal Global ```ts // src/globals/Settings.ts import type { GlobalConfig } from 'payload' export const Settings: GlobalConfig = { slug: 'settings', label: 'Site Settings', fields: [ { name: 'siteName', type: 'text', required: true }, { name: 'siteDescription', type: 'textarea' }, ], } ``` Register it in `payload.config.ts`: ```ts // src/payload.config.ts import { Settings } from './globals/Settings' import { Header } from './globals/Header' export default buildConfig({ globals: [Settings, Header], }) ``` Re-run `pnpm generate:types` after every global change. The slug `settings` produces a `Setting` (or `Settings`) interface in `payload-types.ts`. ## GlobalConfig Reference | Property | Type | Purpose | | --- | --- | --- | | `slug` | `string` | **Required.** Unique key. Becomes `/api/globals/<slug>`, the DB table, and the type name. | | `fields` | `Field[]` | **Required.** Document schema. See the `fields` skill. | | `label` | `string` | Display name in the admin panel. Defaults to an inflected slug. | | `description` | `string \| Component` | Helper text/React component shown under the header for editor context. | | `access` | `object` | Permission rules — `read` / `update` only. See below. | | `hooks` | `object` | Lifecycle callbacks. See below. | | `versions` | `boolean \| object` | Enable version history / drafts. | | `admin` | `object` | Admin panel behavior (group, description, preview, livePreview). | | `endpoints` | `Endpoint[]` | Custom REST routes scoped to this global. | | `graphQL` | `object \| false` | Customize (`name`, `disableQueries`, `disableMutations`) or disable GraphQL. | | `typescript` | `{ interface: string }` | Override the generated TS interface name. | | `custom` | `object` | Extension point for plugin metadata. | | `dbName` | `string` | Custom DB table/collection name. | | `lockDocuments` | `object \| false` | Document-locking behavior in the admin UI. | | `forceSelect` | `object` | Fields always returned regardless of `select`. | ## `admin` Options ```ts // src/globals/Header.ts admin: { group: 'Configuration', // Sidebar grouping; `false` hides nav entry hidden: false, // or (user) => boolean — hides from nav, keeps routes description: 'Primary site navigation', preview: (doc, { req }) => // "Preview" button URL `${process.env.NEXT_PUBLIC_SITE_URL}/preview?secret=${process.env.PREVIEW_SECRET}`, livePreview: { url: ({ data, locale }) => `${process.env.NEXT_PUBLIC_SITE_URL}?draft=true&locale=${locale?.code}`, breakpoints: [ { name: 'mobile', width: 375, height: 667, label: 'Mobile' }, { name: 'desktop', width: 1440, height: 900, label: 'Desktop' }, ], }, } ``` ## Access Control Globals have **only two** access functions — `read` and `update`. There is no `create` or `delete` (a singleton is created on first save and never deleted). Versioned globals also accept `readVersions`. ```ts // src/globals/Settings.ts access: { read: () => true, // Public read update: ({ req: { user } }) => user?.role === 'admin', readVersions: ({ req: { user } }) => Boolean(user), // Versioned globals only } ``` Each function receives `{ req }` (with the authenticated `req.user`); `update` also receives `data` (the incoming update payload). Return a boolean, or a `where` query constraint to restrict access dynamically. See the `access-control` skill for the full pattern. ## Hooks Globals expose six lifecycle hooks, each an array of sync or async functions: | Hook | Fires | Common use | | --- | --- | --- | | `beforeOperation` | Before any operation begins | Mutate `args`, side-effects | | `beforeValidate` | On `update`, before validation | Format/normalize incoming `data` | | `beforeChange` | After validation, before save | Final data shaping (data is valid) | | `afterChange` | After the global is saved | Purge caches, sync to CRM, revalidate | | `beforeRead` | Before `findOne` output transform | Inspect all locales / hidden fields | | `afterRead` | Last step before returning to client | Computed/derived fields | ```ts // src/globals/Settings.ts import type { GlobalConfig } from 'payload' export const Settings: GlobalConfig = { slug: 'settings', hooks: { afterChange: [ async ({ doc, previousDoc, req }) => { // Revalidate the front-end when settings change await fetch(`${process.env.NEXT_PUBLIC_SITE_URL}/api/revalidate?tag=settings`) return doc }, ], }, fields: [/* ... */], } ``` Mutating hooks (`beforeValidate`, `beforeChange`) return the (modified) `data`; read hooks return `doc`. See the `hooks` skill for full argument tables. ## Reading & Writing — Local API ```ts // Read the global (server-side, fully typed) const header = await payload.findGlobal({ slug: 'header', depth: 2, // Resolve relationships 2 levels deep locale: 'en', // Localized field values for this locale fallbackLocale: false, }) // Update the global (data is merged into the single instance) const updated = await payload.updateGlobal({ slug: 'settings', data: { siteName: 'Acme' }, depth: 1, locale: 'en', }) ``` `findGlobal` also accepts `overrideAccess`, `user`, `showHiddenFields`; `updateGlobal` additionally accepts `overrideLock`. `depth` and `locale` work exactly as they do for collection queries — see the `queries` skill. ## Reading & Writing — REST & GraphQL ```http GET /api/globals/header?depth=2&locale=en POST /api/globals/settings # body: JSON of fields to update (REST updates globals via POST) ``` GraphQL auto-generates a query and a mutation per global (e.g. `Header` and `updateHeader`). Customize the GraphQL type name or disable operations via `graphQL: { name, disableQueries, disableMutations }`, or turn it off entirely with `graphQL: false`. ## Versions, Drafts & Localization Enable version history (and optional drafts) the same way collections do: ```ts // src/globals/Homepage.ts versions: { drafts: { autosave: { interval: 800 }, schedulePublish: true }, max: 20, // Keep the last 20 versions } ``` A draft-enabled global gains a `_status` field; fetch the working draft with `payload.findGlobal({ slug: 'homepage', draft: true })`. Any field inside a global can be `localized: true`, in which case `findGlobal`/`updateGlobal` resolve values for the requested `locale`. See the `localization` skill for the localized-field model. ## Project Structure ```txt src/ ├── globals/ │ ├── Settings.ts # Site-wide config │ ├── Header.ts # Localized nav │ └── Footer.ts ├── payload.config.ts ``` Keep each global in its own file; co-locate access functions and hooks in sibling files (`Header.access.ts`, `Header.hooks.ts`) as globals grow. <example> **User**: "Build a Header global with localized nav items linking to pages, public read, and admin-only update, grouped under 'Configuration'." **Solution**: ```ts // src/globals/Header.ts import type { GlobalConfig } from 'payload' export const Header: GlobalConfig = { slug: 'header', label: 'Header', access: { read: () => true, update: ({ req: { user } }) => user?.role === 'admin', }, admin: { group: 'Configuration', description: 'Primary site navigation', }, fields: [ { name: 'navItems', type: 'array', maxRows: 8, fields: [ { name: 'label', type: 'text', required: true, localized: true }, { name: 'page', type: 'relationship', relationTo: 'pages', required: true }, ], }, ], } ``` Register `Header` in `globals: [...]`, then read it on the server: ```ts const header = await payload.findGlobal({ slug: 'header', depth: 1, locale: 'en' }) ``` </example> <example> **User**: "Add an afterChange hook to my Settings global that revalidates the cache." **Solution**: ```ts // src/globals/Settings.ts hooks: { afterChange: [ async ({ doc, req }) => { await fetch(`${process.env.NEXT_PUBLIC_SITE_URL}/api/revalidate?tag=settings`) req.payload.logger.info('Settings updated — cache revalidated') return doc }, ], } ``` </example> ## What this skill does NOT cover - **Field types** inside a global (`text`, `array`, `relationship`, `richText`, etc.) → `fields` skill. - **Multi-document content types** and the full config → `collections` skill. - **Access function signatures, `where` constraints, role logic** → `access-control` skill. - **Hook argument tables and execution order** → `hooks` skill. - **`depth`, `locale`, `where`, pagination, draft querying** → `queries` skill. - **Localized fields, locale config, fallbacks** → `localization` skill.
View on GitHub