--- title: Context label: Context order: 50 desc: Context allows you to pass in extra data that can be shared between hooks keywords: hooks, context, payload context, payloadcontext, data, extra data, shared data, shared, extra --- The `context` object is used to share data across different Hooks. This persists throughout the entire lifecycle of a request and is available within every Hook. By setting properties to `req.context`, you can effectively share logic across multiple Hooks. ## When To Use Context Context gives you a way forward on otherwise difficult problems such as: 1. **Passing data between Hooks**: Needing data in multiple Hooks from a 3rd party API, it could be retrieved and used in `beforeChange` and later used again in an `afterChange` hook without having to fetch it twice. 2. **Preventing infinite loops**: Calling `payload.update()` on the same document that triggered an `afterChange` hook will create an infinite loop, control the flow by assigning a no-op condition to context 3. **Passing data to Local API**: Setting values on the `req.context` and pass it to `payload.create()` you can provide additional data to hooks without adding extraneous fields. 4. **Passing data between hooks and middleware or custom endpoints**: Hooks could set context across multiple collections and then be used in a final `postMiddleware`. ## How To Use Context Let's see examples on how context can be used in the first two scenarios mentioned above: ### Passing Data Between Hooks To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it in the context of a later hook. For example: ```ts import type { CollectionConfig } from 'payload' const Customer: CollectionConfig = { slug: 'customers', hooks: { beforeChange: [ async ({ context, data }) => { // assign the customerData to context for use later context.customerData = await fetchCustomerData(data.customerID) return { ...data, // some data we use here name: context.customerData.name, } }, ], afterChange: [ async ({ context, doc, req }) => { // use context.customerData without needing to fetch it again if (context.customerData.contacted === false) { createTodo('Call Customer', context.customerData) } }, ], }, fields: [ /* ... */ ], } ``` ### Preventing Infinite Loops Let's say you have an `afterChange` hook, and you want to do a calculation inside the hook (as the document ID needed for the calculation is available in the `afterChange` hook, but not in the `beforeChange` hook). Once that's done, you want to update the document with the result of the calculation. Bad example: ```ts import type { CollectionConfig } from 'payload' const Customer: CollectionConfig = { slug: 'customers', hooks: { afterChange: [ async ({ doc, req }) => { await req.payload.update({ // DANGER: updating the same slug as the collection in an afterChange will create an infinite loop! collection: 'customers', id: doc.id, data: { ...(await fetchCustomerData(data.customerID)), }, }) }, ], }, fields: [ /* ... */ ], } ``` Instead of the above, we need to tell the `afterChange` hook to not run again if it performs the update (and thus not update itself again). We can solve that with context. Fixed example: ```ts import type { CollectionConfig } from 'payload' const MyCollection: CollectionConfig = { slug: 'slug', hooks: { afterChange: [ async ({ context, doc, req }) => { // return if flag was previously set if (context.triggerAfterChange === false) { return } await req.payload.update({ collection: contextHooksSlug, id: doc.id, data: { ...(await fetchCustomerData(data.customerID)), }, context: { // set a flag to prevent from running again triggerAfterChange: false, }, }) }, ], }, fields: [ /* ... */ ], } ``` ## TypeScript The default TypeScript interface for `context` is `{ [key: string]: unknown }`. If you prefer a more strict typing in your project or when authoring plugins for others, you can override this using the `declare` syntax. This is known as "type augmentation", a TypeScript feature which allows us to add types to existing types. Simply put this in any `.ts` or `.d.ts` file: ```ts import { RequestContext as OriginalRequestContext } from 'payload' declare module 'payload' { // Create a new interface that merges your additional fields with the original one export interface RequestContext extends OriginalRequestContext { myObject?: string // ... } } ``` This will add the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.