Files
triggerdotdev--trigger.dev/docs/docs.json
T
Eric Allam 16352df366 feat(sdk,core,webapp,react-hooks): named side channels on a Session (#4815)
## Summary

Adds **named side channels** to a Session: durable, two-way realtime
streams that outlive a single run and are shared across every run of the
session. Today a Session has exactly one reserved `.in`/`.out` pair (the
chat transcript). This lets a session hold any number of *named*
channels alongside it, each its own `.in`/`.out` pair, so an agent can
stream out-of-band data (a feed of frames, telemetry, a control channel)
on a stream separate from the transcript while many clients read it
live.

The two properties a named channel adds over the reserved pair:

1. It is addressed by a name that outlives a run and is shared across
runs, not welded to the chat turn loop.
2. Writing its `.in` does **not** wake or trigger a run. A run observes
it by subscribing; an external client writes it without spawning
anything.

This is the generalization half of the Momentic ask (stream browser
screenshots from a `chat.agent` to the frontend on a channel separate
from the chat). It builds directly on the start-from-latest /
`useSessionStream` subscribe seam from #4811.

## Usage

Declare the channel's record types once and infer them on both sides:

```ts
// channels.ts (shared, client imports it type-only)
import { sessions } from "@trigger.dev/sdk";

export const screenshots = sessions.defineChannel<{ out: ScreenshotFrame; in: ViewportControl }>(
  "screenshots"
);
```

Open a channel from a session handle (`sessions.open(id)` returns one
for a known session id). Writing its `.out` is durable, cross-run, and
wakes nothing; a run observes its `.in` by tailing, without suspending:

```ts
import { sessions } from "@trigger.dev/sdk";
import { screenshots } from "./channels";

const channel = sessions.open(sessionId).channel(screenshots);
await channel.out.append(frame);             // frame: ScreenshotFrame (typed from the definition)
channel.in.on((control) => { /* ... */ });    // control: ViewportControl, tail, no suspend
```

Passing the definition types `.out.append` / `.in.on` on the producer
side; a bare name string also works, with records typed `unknown`.

An external client writes the `.in` without waking a run, and reads the
`.out` from React:

```ts
sessions.open(sessionId).channel("screenshots").in.send({ paused: true });

const { records } = useSessionStreamChannel<typeof screenshots>("screenshots", {
  sessionId,
  accessToken,
  io: "out",
  from: "latest",
  maxRecords: 1,
});
```

`session.channel(name)` returns the same `{ in, out }` handle shape as
the reserved pair, so `append` / `pipe` / `writer` / `read` /
`writeControl` / `trimTo` on `.out` and `send` / `on` / `once` / `peek`
on `.in` all carry over. Passing a name other than the declared one is a
type error; a bare-string call without the generic stays valid with
`records` typed `unknown`.

### With `chat.agent`

This is the motivating case: a `chat.agent` answers on the reserved
transcript as usual, and streams screenshot frames on a side channel in
parallel. `chat.channel(name)` opens a channel on the current run's own
Session, so there's no id to thread:

```ts
import { chat } from "@trigger.dev/sdk/ai";
import { streamText } from "ai";
import { screenshots } from "./channels";

export const browserAgent = chat.agent({
  id: "browser-agent",
  run: async ({ messages, signal }) => {
    const frames = chat.channel(screenshots);

    // client pause/resume arrives here without waking a turn
    frames.in.on((control: ViewportControl) => applyViewport(control));

    // frames stream on their own channel, not the chat transcript
    driveBrowser({ signal, onFrame: (frame) => frames.out.append(frame) });

    // the assistant reply still goes to the reserved transcript
    return streamText({ model: openai("gpt-4o"), messages, abortSignal: signal });
  },
});
```

`chat.channel(name)` is a shortcut for `chat.session().channel(name)`;
`chat.session()` returns the current run's full `SessionHandle` if you
need it.

The frontend renders the transcript with `useChat` as before, and the
screenshots with `useSessionStreamChannel<typeof
screenshots>("screenshots", { sessionId: chatId, io: "out", from:
"latest", maxRecords: 1 })`: a live view of the newest frame that
survives across turns (each turn is a new run), because the channel is
keyed on the session, not the run.

### From MCP

An MCP client can observe and write a session's channels with two tools,
built on the same apiClient surface as the hook and the dashboard
viewer:

- `read_session_channel` reads records from a channel (or the reserved
pair). It is a point-in-time drain with cursor pagination
(`afterEventId` / `nextCursor`, `maxRecords`); pass `timeoutInSeconds`
to wait for the next record when none exist yet.
- `write_session_channel` appends one record to a channel's `.in` (an
object or a raw string), so an agent can send control input without
waking a run. `.out` is producer-only, so it is not writable here.

### On the session page

The session detail page lists a session's channels (via an S2 prefix
list in the loader) and shows each as a tab beside `Rendered` and `Raw`.
Selecting a channel renders its records in the same table as the Raw
transcript view, sourced from that channel's `out` and `in` streams.

## How it works

**Addressing.** A channel is a stream name segment:
`sessions/{id}/channels/{name}/{io}`. The reserved pair keeps its
two-part `sessions/{id}/{io}` name for back-compat, and the `channels/`
segment means a user channel named `in`/`out` can never collide with it.
The channel dimension is threaded through the session stream manager
(keyed on `(session, channel, io)`, reserved = absent),
`subscribeToSessionStream`, the session apiClient methods, and the
`realtime.v1.sessions.$session.channels.$channel.$io.{ts,append,records}`
routes. The reserved-pair routes are untouched. The start-from-latest
tail path from #4811 is channel-agnostic, so `from: "latest"` and
`maxRecords` compose unchanged.

**No-wake.** The reserved `.in` append route ensures a run and drains
waitpoints so a chat turn advances. The channel `.in` append route
deliberately does neither: the record lands durably and a run picks it
up when it next subscribes, so writing a side channel can't spawn or
resume a run. A named channel's `.in` is therefore subscribe-only from
the run side (`.on` / `.once` / `.peek`); `.wait()` /
`waitWithIdleTimeout()` throw with a message pointing at the observe
methods.

**Auth.** Channel scope folds into the existing resource id
(`sessions:<key>:channels:<channel>`), so no RBAC grammar change. A
channel route authorizes both the channel-folded id and the bare session
id, which means a session-wide token grants every channel while a
channel-scoped token grants only its own. The per-io rule is preserved
per channel: writing `.out` requires secret-key auth so a browser can't
forge frames; `.in` is writable with the session token.

**Retention.** Channel streams are created on demand on first write and
inherit the org's stream retention (bounded age plus delete-on-empty
from the store's default config), the same as the reserved chat streams.
There is no per-channel control-plane call on the write path. Custom
per-channel retention is deferred until the stream store can set config
inline on the on-demand create, which avoids a control-plane round trip.

**Spans.** Channel writes carry `channel` and `io` attributes, an
accessory chip, and the session icon. Clicking a channel span in the
run's span inspector renders the channel's actual records with the same
viewer the run realtime streams use, rather than the raw properties
JSON.

## Verification

- **Unit (core):** the stream manager isolates channels: two channels on
the same `(session, io)` never cross buffers, and a named channel is
isolated from the reserved pair.
- **Full-stack e2e** against a real stack (webapp, stream store,
Postgres, real runs):
- a named `.out` record is readable back **after the triggering run has
gone terminal** (durable, cross-run);
- a channel `.in` append creates **no** run, while a reserved `.in`
append **does** wake one (the differential is the red/green);
- `from: "latest"` on a named channel delivers the live record and does
**not** replay the backlog from the start;
- the span inspector renders a channel span's records, and the MCP
read/write tools round-trip records on a real session;
  - an invalid channel name is rejected.

## Notes

- **Channel listing works on the self-hosted store too.** The stream
store's list operation is available on s2-lite, so the session page's
channel list is an OSS feature. It is a control-plane call made once per
session-page load (best-effort; a failure just hides the tabs), not on
the write path.
- **The ~1 MiB per-record cap is unchanged.** Large payloads (e.g. raw
screenshots) still need object-store pointers on the channel rather than
inline bytes; that's independent of this change.
- Docs ride this branch: the side channels guide, the
`useSessionStreamChannel` reference, and the MCP tools list are all
updated here.

## Screenshots

<img width="3444" height="1870" alt="CleanShot 2026-08-28 at 21 46
27@2x"
src="https://github.com/user-attachments/assets/c192aaee-b946-4824-87b7-ca057514d25e"
/>
2026-08-29 13:46:38 +00:00

907 lines
28 KiB
JSON

{
"$schema": "https://mintlify.com/docs.json",
"theme": "maple",
"name": "Trigger.dev",
"description": "Trigger.dev is an open source background jobs framework that lets you write reliable workflows in plain async code. Run long-running AI tasks, handle complex background jobs, and build AI agents with built-in queuing, automatic retries, and real-time monitoring. No timeouts, elastic scaling, and zero infrastructure management required.",
"colors": {
"primary": "#A8FF53",
"light": "#A8FF53",
"dark": "#A8FF53"
},
"favicon": "/images/favicon.png",
"contextual": {
"options": ["copy", "view", "claude"]
},
"navigation": {
"dropdowns": [
{
"dropdown": "Documentation",
"description": "Resources for Trigger.dev",
"icon": "book-open",
"groups": [
{
"group": "Getting started",
"pages": [
"introduction",
"quick-start",
"manual-setup",
"video-walkthrough",
"how-it-works",
"limits",
"migrating-from-v3"
]
},
{
"group": "Fundamentals",
"pages": [
{
"group": "Tasks",
"pages": ["tasks/overview", "tasks/schemaTask", "tasks/scheduled"]
},
"triggering",
"runs",
"apikeys"
]
},
{
"group": "Building with AI",
"pages": [
"building-with-ai",
{
"group": "MCP Server",
"pages": ["mcp-introduction", "mcp-tools"]
},
"skills",
"mcp-agent-rules"
]
},
{
"group": "Writing tasks",
"pages": [
"writing-tasks-introduction",
"logging",
"errors-retrying",
{
"group": "Wait",
"pages": ["wait", "wait-for", "wait-until", "wait-for-token"]
},
"queue-concurrency",
"versioning",
"machines",
"idempotency",
"runs/max-duration",
"runs/heartbeats",
"tags",
"runs/metadata",
"tasks/streams",
"run-usage",
"context",
"runs/priority",
"hidden-tasks",
"runs/bulk-actions"
]
},
{
"group": "Agents",
"pages": [
"ai-chat/overview",
"ai-chat/quick-start",
"ai-chat/migrating-from-a-route-handler",
{
"group": "Building agents",
"pages": [
"ai-chat/anatomy",
"ai-chat/backend",
"ai-chat/lifecycle-hooks",
"ai-chat/tools",
"ai-chat/frontend",
"ai-chat/server-chat",
"ai-chat/sessions",
"ai-chat/side-channels",
"ai-chat/chat-local",
"ai-chat/types",
"ai-chat/custom-agents",
"ai-chat/how-it-works"
]
},
{
"group": "Features",
"pages": [
"ai/prompts",
"ai/observability",
"ai-chat/fast-starts",
"ai-chat/compaction",
"ai-chat/prompt-caching",
"ai-chat/pending-messages",
"ai-chat/background-injection",
"ai-chat/actions",
"ai-chat/error-handling"
]
},
{
"group": "Patterns",
"pages": [
"ai-chat/patterns/sub-agents",
"ai-chat/patterns/version-upgrades",
"ai-chat/patterns/database-persistence",
"ai-chat/patterns/persistence-and-replay",
"ai-chat/patterns/branching-conversations",
"ai-chat/patterns/code-sandbox",
"ai-chat/patterns/human-in-the-loop",
"ai-chat/patterns/tool-result-auditing",
"ai-chat/patterns/large-payloads",
"ai-chat/patterns/skills",
"ai-chat/patterns/oom-resilience",
"ai-chat/patterns/recovery-boot",
"ai-chat/patterns/trusted-edge-signals"
]
},
{
"group": "Reference",
"pages": [
"ai-chat/reference",
"ai-chat/client-protocol",
"ai-chat/testing",
"ai-chat/mcp",
"ai-chat/upgrade-guide",
"ai-chat/changelog"
]
}
]
},
{
"group": "Configuration",
"pages": [
"config/config-file",
{
"group": "Build extensions",
"pages": [
"config/extensions/overview",
{
"group": "Built-in extensions",
"pages": [
"config/extensions/prismaExtension",
"config/extensions/pythonExtension",
"config/extensions/playwright",
"config/extensions/puppeteer",
"config/extensions/lightpanda",
"config/extensions/ffmpeg",
"config/extensions/aptGet",
"config/extensions/additionalFiles",
"config/extensions/additionalPackages",
"config/extensions/syncEnvVars",
"config/extensions/esbuildPlugin",
"config/extensions/emitDecoratorMetadata",
"config/extensions/audioWaveform"
]
},
"config/extensions/custom"
]
}
]
},
{
"group": "Deployment",
"pages": [
"deployment/overview",
"deploy-environment-variables",
"github-actions",
"deployment/preview-branches",
"deployment/dev-branches",
"deployment/version-skew-protection",
"deployment/atomic-deployment",
{
"group": "Deployment integrations",
"pages": ["github-integration", "vercel-integration"]
}
]
},
{
"group": "Private networking",
"pages": [
"private-networking/overview",
"private-networking/aws-console-setup",
"private-networking/troubleshooting"
]
},
{
"group": "Realtime",
"pages": [
"realtime/overview",
"realtime/how-it-works",
"realtime/run-object",
"realtime/auth",
{
"group": "React hooks",
"pages": [
"realtime/react-hooks/overview",
"realtime/react-hooks/triggering",
"realtime/react-hooks/subscribe",
"realtime/react-hooks/streams",
"realtime/react-hooks/session-stream",
"realtime/react-hooks/swr",
"realtime/react-hooks/use-wait-token"
]
},
{
"group": "Backend",
"pages": [
"realtime/backend/overview",
"realtime/backend/subscribe",
"realtime/backend/streams"
]
}
]
},
{
"group": "CLI",
"pages": [
"cli-introduction",
{
"group": "Commands",
"pages": [
"cli-deploy-commands",
"cli-dev-commands",
"cli-init-commands",
"cli-list-profiles-commands",
"cli-login-commands",
"cli-logout-commands",
"cli-preview-archive",
"cli-promote-commands",
"cli-switch",
"cli-update-commands",
"cli-whoami-commands"
]
}
]
},
{
"group": "Observability",
"pages": ["observability/query", "observability/dashboards"]
},
{
"group": "Using the Dashboard",
"pages": [
"run-tests",
"troubleshooting-alerts",
"billing-limits",
"replaying",
"bulk-actions"
]
},
{
"group": "Troubleshooting",
"pages": [
"troubleshooting",
"database-connections",
"how-to-reduce-your-spend",
"troubleshooting-debugging-in-vscode",
"upgrading-packages",
"troubleshooting-uptime-status",
"troubleshooting-github-issues",
"request-feature"
]
},
{
"group": "Self-hosting",
"pages": [
"self-hosting/overview",
"self-hosting/docker",
"self-hosting/kubernetes",
"self-hosting/security",
{
"group": "Environment variables",
"pages": ["self-hosting/env/webapp", "self-hosting/env/supervisor"]
}
]
},
{
"group": "Open source",
"pages": ["open-source-contributing", "github-repo", "changelog", "roadmap"]
},
{
"group": "Help",
"pages": ["community", "help-slack", "help-email"]
}
]
},
{
"dropdown": "API reference",
"description": "The Trigger.dev API",
"icon": "code",
"groups": [
{
"group": "API reference",
"pages": [
"management/overview",
"management/authentication",
"management/multiple-clients",
"management/errors-and-retries",
"management/auto-pagination",
"management/advanced-usage"
]
},
{
"group": "Tasks API",
"pages": [
"management/tasks/trigger",
"management/tasks/batch-trigger",
"management/tasks/trigger-batch"
]
},
{
"group": "Batches API",
"pages": [
"management/batches/create",
"management/batches/retrieve",
"management/batches/retrieve-results",
"management/batches/stream-items"
]
},
{
"group": "Runs API",
"pages": [
"management/runs/list",
"management/runs/retrieve",
"management/runs/replay",
"management/runs/cancel",
"management/runs/reschedule",
"management/runs/update-metadata",
"management/runs/add-tags",
"management/runs/retrieve-events",
"management/runs/retrieve-trace",
"management/runs/retrieve-result"
]
},
{
"group": "Bulk actions API",
"pages": [
"management/bulk-actions/create",
"management/bulk-actions/list",
"management/bulk-actions/retrieve",
"management/bulk-actions/abort"
]
},
{
"group": "Errors API",
"pages": [
"management/errors/list",
"management/errors/retrieve",
"management/errors/resolve",
"management/errors/ignore",
"management/errors/unresolve"
]
},
{
"group": "Queues API",
"pages": [
"management/queues/list",
"management/queues/retrieve",
"management/queues/pause",
"management/queues/concurrency-override",
"management/queues/concurrency-reset"
]
},
{
"group": "Schedules API",
"pages": [
"management/schedules/list",
"management/schedules/create",
"management/schedules/retrieve",
"management/schedules/update",
"management/schedules/delete",
"management/schedules/deactivate",
"management/schedules/activate",
"management/schedules/timezones"
]
},
{
"group": "Env Vars API",
"pages": [
"management/envvars/list",
"management/envvars/import",
"management/envvars/create",
"management/envvars/retrieve",
"management/envvars/update",
"management/envvars/delete"
]
},
{
"group": "Deployments API",
"pages": [
"management/deployments/list",
"management/deployments/retrieve",
"management/deployments/get-latest",
"management/deployments/promote"
]
},
{
"group": "Waitpoints API",
"pages": [
"management/waitpoints/create",
"management/waitpoints/list",
"management/waitpoints/retrieve",
"management/waitpoints/complete",
"management/waitpoints/complete-callback"
]
},
{
"group": "Sessions API",
"pages": [
"management/sessions/create",
"management/sessions/list",
"management/sessions/retrieve",
"management/sessions/update",
"management/sessions/close",
"management/sessions/channels"
]
},
{
"group": "Query API",
"pages": [
"management/query/execute",
"management/query/schema",
"management/query/dashboards"
]
}
]
},
{
"dropdown": "Guides & examples",
"description": "A great way to get started",
"icon": "books",
"groups": [
{
"group": "Introduction",
"pages": ["guides/introduction"]
},
{
"group": "Frameworks",
"pages": [
"guides/frameworks/bun",
"guides/frameworks/nextjs",
"guides/frameworks/nodejs",
"guides/frameworks/remix",
"guides/community/sveltekit"
]
},
{
"group": "Guides",
"pages": [
{
"group": "AI Agents",
"icon": {
"name": "microchip-ai",
"style": "regular"
},
"pages": [
"guides/ai-agents/overview",
"guides/ai-agents/chat-agent",
"guides/ai-agents/generate-translate-copy",
"guides/ai-agents/route-question",
"guides/ai-agents/respond-and-check-content",
"guides/ai-agents/translate-and-refine",
"guides/ai-agents/verify-news-article"
]
},
"guides/ai-agents/claude-code-trigger",
"guides/frameworks/drizzle",
"guides/frameworks/prisma",
"guides/frameworks/nango",
"guides/frameworks/sequin",
{
"group": "Supabase",
"icon": {
"name": "bolt",
"style": "solid"
},
"pages": [
"guides/frameworks/supabase-guides-overview",
"guides/frameworks/supabase-edge-functions-basic",
"guides/frameworks/supabase-edge-functions-database-webhooks",
"guides/frameworks/supabase-authentication"
]
},
{
"group": "Webhooks",
"icon": {
"name": "webhook",
"style": "solid"
},
"pages": [
"guides/frameworks/webhooks-guides-overview",
"guides/frameworks/nextjs-webhooks",
"guides/frameworks/remix-webhooks",
"guides/examples/stripe-webhook",
"guides/examples/hookdeck-webhook"
]
}
]
},
{
"group": "Migration guides",
"pages": ["migration-mergent", "migration-n8n"]
},
{
"group": "Use cases",
"pages": [
"guides/use-cases/overview",
"guides/use-cases/data-processing-etl",
"guides/use-cases/media-generation",
"guides/use-cases/media-processing",
"guides/use-cases/marketing"
]
},
{
"group": "Example projects",
"pages": [
"guides/example-projects/anchor-browser-web-scraper",
"guides/example-projects/batch-llm-evaluator",
"guides/example-projects/claude-changelog-generator",
"guides/example-projects/claude-github-wiki",
"guides/example-projects/claude-thinking-chatbot",
"guides/example-projects/clickhouse-chat-agent",
"guides/example-projects/cursor-background-agent",
"guides/example-projects/human-in-the-loop-workflow",
"guides/example-projects/mastra-agents-with-memory",
"guides/example-projects/meme-generator-human-in-the-loop",
"guides/example-projects/openai-agents-sdk-typescript-playground",
"guides/example-projects/product-image-generator",
"guides/example-projects/realtime-csv-importer",
"guides/example-projects/realtime-fal-ai",
"guides/example-projects/smart-spreadsheet",
"guides/example-projects/turborepo-monorepo-prisma",
"guides/example-projects/vercel-ai-sdk-deep-research",
"guides/example-projects/vercel-ai-sdk-image-generator"
]
},
{
"group": "Python guides",
"pages": [
"guides/example-projects/openai-agent-sdk-guardrails",
"guides/python/python-image-processing",
"guides/python/python-doc-to-markdown",
"guides/python/python-crawl4ai",
"guides/python/python-pdf-form-extractor"
]
},
{
"group": "Example tasks",
"pages": [
"guides/examples/dall-e3-generate-image",
"guides/examples/deepgram-transcribe-audio",
"guides/examples/fal-ai-image-to-cartoon",
"guides/examples/fal-ai-realtime",
"guides/examples/ffmpeg-video-processing",
"guides/examples/firecrawl-url-crawl",
"guides/examples/lightpanda",
"guides/examples/libreoffice-pdf-conversion",
"guides/examples/open-ai-with-retrying",
"guides/examples/pdf-to-image",
"guides/examples/puppeteer",
"guides/examples/react-pdf",
"guides/examples/react-email",
"guides/examples/replicate-image-generation",
"guides/examples/resend-email-sequence",
"guides/examples/satori",
"guides/examples/scrape-hacker-news",
"guides/examples/sentry-error-tracking",
"guides/examples/sharp-image-processing",
"guides/examples/supabase-database-operations",
"guides/examples/supabase-storage-upload",
"guides/examples/vercel-ai-sdk",
"guides/examples/vercel-sync-env-vars"
]
},
{
"group": "Community packages",
"pages": [
"guides/community/dotenvx",
"guides/community/fatima",
"guides/community/rate-limiter",
"guides/community/sveltekit"
]
}
]
}
]
},
"logo": {
"light": "/logo/light.png",
"dark": "/logo/dark.png",
"href": "https://trigger.dev"
},
"api": {
"openapi": ["openapi.yml", "v3-openapi.yaml"],
"playground": {
"display": "simple"
}
},
"styling": {
"codeblocks": {
"theme": "css-variables"
}
},
"appearance": {
"default": "dark",
"strict": true
},
"background": {
"color": {
"light": "#fff",
"dark": "#121317"
}
},
"navbar": {
"primary": {
"type": "github",
"href": "https://github.com/triggerdotdev/trigger.dev"
}
},
"footer": {
"socials": {
"x": "https://twitter.com/triggerdotdev",
"github": "https://github.com/triggerdotdev",
"linkedin": "https://www.linkedin.com/company/triggerdotdev"
},
"links": [
{
"header": "Developers",
"items": [
{
"label": "Changelog",
"href": "https://trigger.dev/changelog"
},
{
"label": "Contributing",
"href": "https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md"
},
{
"label": "Open source",
"href": "https://github.com/triggerdotdev/trigger.dev?tab=Apache-2.0-1-ov-file#readme"
},
{
"label": "GitHub",
"href": "https://github.com/triggerdotdev/trigger.dev"
},
{
"label": "OSS Friends",
"href": "https://trigger.dev/oss-friends"
}
]
},
{
"header": "Product",
"items": [
{
"label": "Pricing",
"href": "https://trigger.dev/pricing"
},
{
"label": "How it works",
"href": "https://trigger.dev/#how-it-works"
},
{
"label": "Features",
"href": "https://trigger.dev/product"
},
{
"label": "Roadmap",
"href": "https://feedback.trigger.dev/roadmap"
},
{
"label": "FAQs",
"href": "https://trigger.dev/pricing#faqs"
},
{
"label": "Uptime status",
"href": "https://status.trigger.dev/"
}
]
},
{
"header": "Company",
"items": [
{
"label": "Blog",
"href": "https://trigger.dev/blog"
},
{
"label": "Contact",
"href": "https://trigger.dev/contact"
},
{
"label": "Careers",
"href": "https://trigger.dev/jobs"
},
{
"label": "Privacy",
"href": "https://trigger.dev/legal/privacy"
},
{
"label": "Terms of service",
"href": "https://trigger.dev/legal"
}
]
}
]
},
"redirects": [
{
"source": "/config/extensions",
"destination": "/config/extensions/overview",
"permanent": true
},
{
"source": "/upgrading-beta",
"destination": "/upgrading-packages",
"permanent": true
},
{
"source": "/guides/new-build-system-preview",
"destination": "/upgrading-packages",
"permanent": true
},
{
"source": "/cli-dev",
"destination": "/cli-dev-commands",
"permanent": true
},
{
"source": "/cli-deploy",
"destination": "/cli-deploy-commands",
"permanent": true
},
{
"source": "/cli-development-commands",
"destination": "/cli-dev-commands",
"permanent": true
},
{
"source": "/v3/feature-matrix",
"destination": "https://feedback.trigger.dev/roadmap"
},
{
"source": "/v3/upgrading-from-v2",
"destination": "/guides/use-cases/upgrading-from-v2"
},
{
"source": "/open-source-self-hosting",
"destination": "/self-hosting/overview"
},
{
"source": "/v3/open-source-self-hosting",
"destination": "/self-hosting/overview"
},
{
"source": "/v3/:slug*",
"destination": "/:slug*"
},
{
"source": "/reattempting-replaying",
"destination": "/replaying"
},
{
"source": "/management/runs/bulk-actions",
"destination": "/runs/bulk-actions"
},
{
"source": "/tasks-overview",
"destination": "/tasks/overview"
},
{
"source": "/tasks-scheduled",
"destination": "/tasks/scheduled"
},
{
"source": "/trigger-folder",
"destination": "/config/config-file"
},
{
"source": "/trigger-config",
"destination": "/config/config-file"
},
{
"source": "/guides/frameworks",
"destination": "/guides/frameworks/nextjs"
},
{
"source": "/guides/frameworks/introduction",
"destination": "/guides/introduction"
},
{
"source": "/guides/examples/intro",
"destination": "/guides/introduction"
},
{
"source": "/examples/:slug*",
"destination": "/guides/examples/:slug*"
},
{
"source": "/realtime",
"destination": "/realtime/overview"
},
{
"source": "/runs-and-attempts",
"destination": "/runs"
},
{
"source": "/frontend/react-hooks",
"destination": "/realtime/react-hooks/overview"
},
{
"source": "/frontend/overview",
"destination": "/realtime/auth"
},
{
"source": "/frontend/react-hooks/overview",
"destination": "/realtime/react-hooks/overview"
},
{
"source": "/frontend/react-hooks/realtime",
"destination": "/realtime/react-hooks/realtime"
},
{
"source": "/frontend/react-hooks/triggering",
"destination": "/realtime/react-hooks/triggering"
},
{
"source": "/realtime/backend",
"destination": "/realtime/backend/overview"
},
{
"source": "/realtime/streams",
"destination": "/realtime/backend/streams"
},
{
"source": "/realtime/react-hooks",
"destination": "/realtime/react-hooks/overview"
},
{
"source": "/realtime/subscribe-to-run",
"destination": "/realtime/backend/subscribe"
},
{
"source": "/realtime/subscribe-to-runs-with-tag",
"destination": "/realtime/backend/subscribe"
},
{
"source": "/realtime/subscribe-to-batch",
"destination": "/realtime/backend/subscribe"
},
{
"source": "/management/projects/runs",
"destination": "/management/overview"
},
{
"source": "/guides/cursor-rules",
"destination": "/mcp-agent-rules"
},
{
"source": "/agents/rules/overview",
"destination": "/mcp-agent-rules"
},
{
"source": "/upgrade-to-v4",
"destination": "/migrating-from-v3"
},
{
"source": "/insights/query",
"destination": "/observability/query"
},
{
"source": "/insights/metrics",
"destination": "/observability/dashboards"
},
{
"source": "/guides/ai-chat",
"destination": "/ai-chat/overview"
},
{
"source": "/deployment/vercel-skew-protection",
"destination": "/deployment/version-skew-protection",
"permanent": true
}
]
}