vault backup: 2026-05-15 15:49:53

This commit is contained in:
Vadym Samoilenko 2026-05-15 15:49:53 +01:00
parent dfa0a4ce7d
commit 885dc09d7f
2 changed files with 161 additions and 0 deletions

View file

@ -88,6 +88,7 @@
| [[wiki/payloadcms/fields-ui\|UI Field]] | Presentational-only field — inject arbitrary React components into Admin Panel Edit/List views; no data stored; use for action buttons, context text, custom controls | raw/fields__ui.md | 2026-05-15 |
| [[wiki/payloadcms/fields-upload\|Upload Field]] | Reference upload-enabled Collection docs as thumbnail — hasMany, polymorphic multi-collection, filterOptions, bi-directional via Join | raw/fields__upload.md | 2026-05-15 |
| [[wiki/payloadcms/graphql-overview\|GraphQL API — Overview]] | Auto-generated GraphQL endpoint: queries/mutations for Collections, Globals, Preferences; playground, complexity limits, custom validation rules | raw/graphql__overview.md | 2026-05-15 |
| [[wiki/payloadcms/hooks-collections\|Collection Hooks]] | All 18 collection hook types (write/read/delete/auth lifecycle), `data` vs `originalDoc` gotcha, auth hooks, TypeScript generics | raw/hooks__collections.md | 2026-05-15 |
| [[wiki/payloadcms/concepts-overview\|Core Concepts]] | Config, Collections, Globals, Fields, Hooks, Auth, Access Control, Admin Panel; Local/REST/GraphQL APIs; package structure | raw/getting-started__concepts.md | 2026-05-15 |
| [[wiki/payloadcms/installation\|Installation]] | Requirements (Node 24+, Next.js 16.2.6+), create-payload-app quickstart, manual install steps, withPayload ESM config, tsconfig path alias | raw/getting-started__installation.md | 2026-05-15 |
| [[wiki/payloadcms/graphql-extending\|GraphQL — Custom Queries and Mutations]] | Add custom GraphQL ops via `graphQL.queries`/`graphQL.mutations` in buildConfig; resolver signature, `depth: 0` gotcha, `buildPaginatedListType`, collection graphQL types | raw/graphql__extending.md | 2026-05-15 |

View file

@ -0,0 +1,160 @@
---
title: "Collection Hooks"
aliases: [collection-hooks, payload-collection-hooks]
tags: [payloadcms, hooks, collections, lifecycle, auth]
sources: [raw/hooks__collections.md]
created: 2026-05-15
updated: 2026-05-15
---
Collection Hooks run on Documents within a specific [[wiki/payloadcms/collection-config|Collection]], letting you execute custom logic at precise moments in the Document lifecycle.
```ts
export const MyCollection: CollectionConfig = {
hooks: {
beforeOperation: [fn],
beforeValidate: [fn],
beforeChange: [fn],
afterChange: [fn],
beforeRead: [fn],
afterRead: [fn],
beforeDelete: [fn],
afterDelete: [fn],
afterOperation: [fn],
afterError: [fn],
// Auth-only:
beforeLogin: [fn], afterLogin: [fn], afterLogout: [fn],
afterRefresh: [fn], afterMe: [fn], afterForgotPassword: [fn],
refresh: [fn], me: [fn],
},
}
```
Each hook accepts an **array** of synchronous or asynchronous functions.
---
## Hook Reference
### Write Lifecycle (create / update)
| Hook | When | Typical use |
|------|------|-------------|
| `beforeOperation` | Before any operation starts | Modify operation args, early side-effects |
| `beforeValidate` | Before server validation | Format / enrich incoming data |
| `beforeChange` | After validation, before DB write | Data transformation, enforce business rules |
| `afterChange` | After DB write | Sync to CRM, recalculate aggregates |
**Order:** `beforeOperation``beforeValidate` → client `validate` → server `validate``beforeChange` → DB write → `afterChange``afterOperation`
### Read Lifecycle
| Hook | When | Notes |
|------|------|-------|
| `beforeRead` | Before locale-flattening / hidden-field removal | Has access to **all locales** and hidden fields |
| `afterRead` | Last step before response | Locales flattened, protected fields removed |
### Delete Lifecycle
| Hook | Return value |
|------|-------------|
| `beforeDelete` | Discarded |
| `afterDelete` | Discarded |
### Error Hook
`afterError` — fires on any Payload application error. Use for Sentry/DataDog/email alerts. Can transform the result object and HTTP status code.
---
## Key Arguments
### `data` vs `originalDoc`
> **`data` is a delta** — it only contains fields being changed, NOT the full document.
```ts
// On UPDATE — get id from originalDoc, not data
const id = operation === 'update' ? originalDoc.id : undefined
// On CREATE — id is not available until afterChange
```
| Hook | `data` | `originalDoc` | `doc` |
|------|--------|--------------|-------|
| `beforeValidate` | changed fields | full pre-change doc (update only) | — |
| `beforeChange` | changed fields | full pre-change doc (update only) | — |
| `afterChange` | changed fields | — | full resulting doc |
| `afterRead` | — | — | full resulting doc |
### Common Arguments (all hooks)
- **`collection`** — Collection config object
- **`context`** — custom pass-through between hooks (see [[wiki/payloadcms/hooks|Hooks overview]])
- **`req`** — Web Request (mocked for [[wiki/payloadcms/local-api|Local API]])
- **`operation`** — `'create' | 'update' | 'delete' | 'find' | ...`
---
## Auth-Enabled Hooks
For collections with `auth: true`. See [[wiki/payloadcms/authentication-overview|Authentication Overview]].
| Hook | Fires | Can modify |
|------|-------|-----------|
| `beforeLogin` | After credentials matched, before token | Return modified user or throw to deny login |
| `afterLogin` | After successful login | Return modified user |
| `afterLogout` | After logout | Side-effects only |
| `afterRefresh` | After token refresh | Side-effects only |
| `afterMe` | After `/me` request | Return modified response |
| `afterForgotPassword` | After forgot-password | Return value discarded |
| `refresh` | Replaces default refresh logic | Return value skips default operation |
| `me` | Replaces default me logic | Return value skips default operation |
---
## TypeScript
```ts
import type {
CollectionBeforeOperationHook,
CollectionBeforeValidateHook,
CollectionBeforeChangeHook,
CollectionAfterChangeHook,
CollectionAfterReadHook,
CollectionBeforeReadHook,
CollectionBeforeDeleteHook,
CollectionAfterDeleteHook,
CollectionBeforeLoginHook,
CollectionAfterLoginHook,
CollectionAfterLogoutHook,
CollectionAfterRefreshHook,
CollectionAfterMeHook,
CollectionAfterForgotPasswordHook,
CollectionRefreshHook,
CollectionMeHook,
} from 'payload'
// Generic typing for doc/data
const afterChangeHook: CollectionAfterChangeHook<Post> = async ({ doc, previousDoc }) => {
return doc
}
```
---
## Key Takeaways
- **`data` is always a partial delta** — never assume `id` or unchanged fields are present; use `originalDoc` on updates, `afterChange` for the `id` on creates
- **`beforeChange` data is unvalidated** — treat it as raw user input; required fields may be missing
- **`beforeRead`** sees all locales and hidden fields before Payload strips them — use it for internal transforms
- **`afterRead`** sees the cleaned, user-visible document — use it for computed props exposed to clients
- Auth hooks (`beforeLogin`, `refresh`, `me`) can **replace default behavior** by returning early — powerful but be careful
- `afterError` hook is the right place for Sentry / alerting integration, not `try/catch` in every hook
- Field-level hooks are an alternative for isolating logic — see [[wiki/payloadcms/hooks|Hooks Overview]]
---
## Sources
- `raw/hooks__collections.md` (source: https://payloadcms.com/docs/hooks/collections)