# Context

Source: https://payloadcms.com/docs/beta/hooks/context

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',
          overrideAccess: true,
          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,
          overrideAccess: true,
          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 module` syntax.

This is known as [module augmentation / declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation), a TypeScript feature which allows us to add properties to existing types. Simply put this in any `.ts` or `.d.ts` file:

```ts
declare module 'payload' {
  // Augment the RequestContext interface to include your custom properties
  export interface RequestContext {
    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 module augmentation can mess up your types if you do it wrong.
