workflow
Version:
Workflow DevKit - Build durable, resilient, and observable workflows
198 lines (142 loc) • 5.34 kB
text/mdx
---
title: createHook
description: Create a low-level hook to resume workflows with arbitrary payloads.
type: reference
summary: Use createHook to pause a workflow and resume it with an arbitrary payload from an external system.
prerequisites:
- /docs/foundations/hooks
related:
- /docs/api-reference/workflow/define-hook
- /docs/api-reference/workflow/create-webhook
---
Creates a low-level hook primitive that can be used to resume a workflow run with arbitrary payloads.
Hooks allow external systems to send data to a paused workflow without the HTTP-specific constraints of webhooks. They're identified by a token and can receive any serializable payload.
```ts lineNumbers
import { createHook } from "workflow"
export async function hookWorkflow() {
"use workflow";
// `using` automatically disposes the hook when it goes out of scope
using hook = createHook(); // [!code highlight]
const result = await hook; // Suspends the workflow until the hook is resumed
}
```
## API Signature
### Parameters
<TSDoc
definition={`
import { createHook } from "workflow";
export default createHook;`
}
showSections={['parameters']}
/>
#### HookOptions
<TSDoc
definition={`
import type { HookOptions } from "workflow";
export default HookOptions;`
}
/>
### Returns
<TSDoc
definition={`
import { createHook } from "workflow";
export default createHook;`}
showSections={['returns']}
/>
#### Hook
<TSDoc
definition={`
import type { Hook } from "workflow";
export default Hook;`}
/>
The returned `Hook` object also implements `AsyncIterable<T>`, which allows you to iterate over incoming payloads using `for await...of` syntax.
## Examples
### Basic Usage
When creating a hook, you can specify a payload type for automatic type safety:
```typescript lineNumbers
import { createHook } from "workflow"
export async function approvalWorkflow() {
"use workflow";
using hook = createHook<{ approved: boolean; comment: string }>(); // [!code highlight]
console.log("Send approval to token:", hook.token);
const result = await hook;
if (result.approved) {
console.log("Approved with comment:", result.comment);
}
}
```
### Customizing Tokens
Tokens are used to identify a specific hook. You can customize the token to be more specific to a use case.
```typescript lineNumbers
import { createHook } from "workflow";
export async function slackBotWorkflow(channelId: string) {
"use workflow";
// Token constructed from channel ID
using hook = createHook<SlackMessage>({ // [!code highlight]
token: `slack_messages:${channelId}`, // [!code highlight]
}); // [!code highlight]
for await (const message of hook) {
if (message.text === "/stop") {
break;
}
await processMessage(message);
}
}
```
### Waiting for Multiple Payloads
You can also wait for multiple payloads by using the `for await...of` syntax.
```typescript lineNumbers
import { createHook } from "workflow"
export async function collectHookWorkflow() {
"use workflow";
using hook = createHook<{ message: string; done?: boolean }>();
const payloads = [];
for await (const payload of hook) { // [!code highlight]
payloads.push(payload);
if (payload.done) break;
}
return payloads;
}
```
### Disposing Hooks Early
You can dispose a hook early to release its token for reuse by another workflow. This is useful for handoff patterns where one workflow needs to transfer a hook token to another workflow while still running.
```typescript lineNumbers
import { createHook } from "workflow"
export async function handoffWorkflow(channelId: string) {
"use workflow";
const hook = createHook<{ message: string; handoff?: boolean }>({
token: `channel:${channelId}`
});
for await (const payload of hook) {
console.log("Received:", payload.message);
if (payload.handoff) {
hook.dispose(); // [!code highlight] Release the token for another workflow
break;
}
}
// Continue with other work while another workflow uses the token
}
```
After calling `dispose()`, the hook will no longer receive events and its token becomes available for other workflows to use.
### Automatic Disposal with `using`
Hooks implement the [TC39 Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management) proposal, allowing automatic disposal with the `using` keyword:
```typescript lineNumbers
import { createHook } from "workflow"
export async function scopedHookWorkflow(channelId: string) {
"use workflow";
{
using hook = createHook<{ message: string }>({ // [!code highlight]
token: `channel:${channelId}`
});
const payload = await hook;
console.log("Received:", payload.message);
} // hook is automatically disposed here // [!code highlight]
// Token is now available for other workflows to use
console.log("Hook disposed, continuing with other work...");
}
```
This is equivalent to manually calling `dispose()` but ensures the hook is always cleaned up, even if an error occurs.
## Related Functions
- [`defineHook()`](/docs/api-reference/workflow/define-hook) - Type-safe hook helper
- [`resumeHook()`](/docs/api-reference/workflow-api/resume-hook) - Resume a hook with a payload
- [`createWebhook()`](/docs/api-reference/workflow/create-webhook) - Higher-level HTTP webhook abstraction