From 54d22e9ee1dd69cb72869e0339703b120ea6ab69 Mon Sep 17 00:00:00 2001 From: Iss <74388823+isshaddad@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:09:48 -0400 Subject: [PATCH] docs: add per-task middleware section to tasks overview (#3197) --- docs/tasks/overview.mdx | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/tasks/overview.mdx b/docs/tasks/overview.mdx index 6e638dd84..d7cb4d8f4 100644 --- a/docs/tasks/overview.mdx +++ b/docs/tasks/overview.mdx @@ -168,7 +168,7 @@ You can override this per-trigger by passing `ttl` in the trigger options, or se You can register global lifecycle hooks that are executed for all runs, regardless of the task. While you can still define these in the `trigger.config.ts` file, you can also register them anywhere in your codebase: -```ts +```typescript import { tasks } from "@trigger.dev/sdk"; tasks.onStartAttempt(({ ctx, payload, task }) => { @@ -262,7 +262,7 @@ tasks.onResume("db", async ({ ctx, payload, task }) => { You can access the database client using `getDb()` in your tasks `run` function and all your hooks (global or task specific): -```ts +```typescript import { getDb } from "./db"; export const myTask = task({ @@ -273,6 +273,28 @@ export const myTask = task({ }); ``` +#### Per-task middleware + +You can also define middleware per task by passing the `middleware` option in the task definition. This runs after global middleware and before the `run` function. Use it when only specific tasks need certain locals or setup: + +```typescript +import { task, locals } from "@trigger.dev/sdk"; + +const myLocal = locals.create("myLocal"); + +export const myTask = task({ + id: "my-task", + middleware: async ({ payload, ctx, next }) => { + locals.set(myLocal, "some-value"); + await next(); + }, + run: async (payload) => { + const value = locals.getOrThrow(myLocal); + // ... + }, +}); +``` + ### `onStartAttempt` function The `onStartAttempt` function was introduced in v4.1.0 @@ -323,7 +345,7 @@ export const taskWithOnStartAttempt = task({ These lifecycle hooks allow you to run code when a run is paused or resumed because of a wait: -```ts +```typescript export const myTask = task({ id: "my-task", onWait: async ({ wait }) => { @@ -466,7 +488,7 @@ Read more about `catchError` in our [Errors and Retrying guide](/errors-retrying You can define an `onCancel` hook that is called when a run is cancelled. This is useful if you want to clean up any resources that were allocated for the run. -```ts +```typescript tasks.onCancel(({ ctx, signal }) => { console.log("Run cancelled", signal); }); @@ -474,7 +496,7 @@ tasks.onCancel(({ ctx, signal }) => { You can use the `onCancel` hook along with the `signal` passed into the run function to interrupt a call to an external service, for example using the [streamText](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) function from the AI SDK: -```ts +```typescript import { logger, tasks, schemaTask } from "@trigger.dev/sdk"; import { streamText } from "ai"; import { z } from "zod"; @@ -528,7 +550,7 @@ export const interruptibleChat = schemaTask({ The `onCancel` hook can optionally wait for the `run` function to finish, and access the output of the run: -```ts +```typescript import { logger, task } from "@trigger.dev/sdk"; import { setTimeout } from "node:timers/promises";