Skip to content

Commit 245576b

Browse files
authored
docs: hooks terminology update (#13847)
Addresses feedback from #10460 It is a bit misleading the way it is worded currently—so I've updated the verbiage accordingly and provided code snippets
1 parent 2410296 commit 245576b

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

docs/hooks/overview.mdx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,15 @@ The following arguments are provided to the `afterError` Hook:
8787
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. This will be `undefined` if the hook is executed from a non-collection endpoint or GraphQL. |
8888
| **`result`** | The formatted error result object, available if the hook is executed from a REST context. |
8989

90-
## Async vs. Synchronous
90+
## Awaited vs. non-blocking hooks
9191

92-
All Hooks can be written as either synchronous or asynchronous functions. Choosing the right type depends on your use case, but switching between the two is as simple as adding or removing the `async` keyword.
92+
Hooks can either block the request until they finish or run without blocking it. What matters is whether your hook returns a Promise.
9393

94-
#### Asynchronous
94+
Awaited (blocking): If your hook returns a Promise (for example, if it’s declared async), Payload will wait for it to resolve before continuing that lifecycle step. Use this when your hook needs to modify data or influence the response. Hooks that return Promises run in series at the same lifecycle stage.
9595

96-
If the Hook should modify data before a Document is updated or created, and it relies on asynchronous actions such as fetching data from a third party, it might make sense to define your Hook as an asynchronous function. This way you can be sure that your Hook completes before the operation's lifecycle continues.
96+
Non-blocking (sometimes called “fire-and-forget”): If your hook does not return a Promise (returns nothing), Payload will not wait for it to finish. This can be useful for side-effects that don’t affect the outcome of the operation, but keep in mind that any work started this way might continue after the request has already completed.
9797

98-
Async hooks are run in series - so if you have two async hooks defined, the second hook will wait for the first to complete before it starts.
98+
**Declaring a function with async does not make it “synchronous.” The async keyword simply makes the function return a Promise automatically — which is why Payload then awaits it.**
9999

100100
<Banner type="success">
101101
**Tip:** If your hook executes a long-running task that doesn't affect the
@@ -104,9 +104,24 @@ Async hooks are run in series - so if you have two async hooks defined, the seco
104104
continue processing without waiting for the task to complete.
105105
</Banner>
106106

107-
#### Synchronous
107+
**Awaited**
108108

109-
If your Hook simply performs a side-effect, such as mutating document data, it might be okay to define it synchronously, so the Payload operation does not have to wait for your hook to complete.
109+
```ts
110+
const beforeChange = async ({ data }) => {
111+
const enriched = await fetchProfile(data.userId) // Payload waits here
112+
return { ...data, profile: enriched }
113+
}
114+
```
115+
116+
**Non-blocking**
117+
118+
```ts
119+
const afterChange = ({ doc }) => {
120+
// Trigger side-effect without blocking
121+
void pingAnalyticsService(doc.id)
122+
// No return → Payload does not wait
123+
}
124+
```
110125

111126
## Server-only Execution
112127

0 commit comments

Comments
 (0)