diff --git a/docs/apikeys.mdx b/docs/apikeys.mdx
index 5b9eeef1a1..38626760eb 100644
--- a/docs/apikeys.mdx
+++ b/docs/apikeys.mdx
@@ -39,7 +39,7 @@ The default URL is `https://api.trigger.dev`.
If you prefer to manually configure the SDK, you can call the `configure` method:
```ts
-import { configure } from "@trigger.dev/sdk/v3";
+import { configure } from "@trigger.dev/sdk";
import { myTask } from "./trigger/myTasks";
configure({
diff --git a/docs/bulk-actions.mdx b/docs/bulk-actions.mdx
index 0e2b4468a3..04d0551c93 100644
--- a/docs/bulk-actions.mdx
+++ b/docs/bulk-actions.mdx
@@ -3,16 +3,10 @@ title: "Bulk actions"
description: "Perform actions like replay and cancel on multiple runs at once."
---
-Bulk actions allow you to perform operations like replaying or canceling on multiple runs at once. This is especially useful when you need to retry a batch of failed runs with a new version of your code, or when you need to cancel multiple in-progress runs.
-
-## Bulk replaying
-
-You can replay multiple runs at once by selecting them from the table on the Runs page using the checkbox on the left hand side of the row. Then click the "Replay runs" button from the bulk action bar that appears at the bottom of the screen.
-
-This is especially useful if you have lots of failed runs and want to run them all again. To do this, first filter the runs by the status you want, then select all the runs you want to replay and click the "Replay runs" button from the bulk action bar at the bottom of the page.
+Bulk actions allow you to perform replaying and canceling on multiple runs at once. This is especially useful when you need to retry a batch of failed runs with a new version of your code, or when you need to cancel multiple in-progress runs.
-## Bulk canceling
+## How to create a new bulk action
+
+ Open the bulk action panel from the top right of the runs page
+
+
+
+
+ Filter the runs table to show the runs you want to bulk action
+
+ Alternatively, you can select individual runs
+
+ Choose the runs you want to bulk action
+
+ Name your bulk action (optional)
+
+ Choose the action you want to perform, replay or cancel
+
+ Click the "Replay" or "Cancel" button and confirm in the dialog
-Similar to replaying multiple runs, you can cancel multiple runs at once. This is particularly useful when you have a batch of runs that you want to stop, perhaps because they were triggered with incorrect parameters or are no longer needed.
+
-To cancel multiple runs:
+ You'll now view the bulk action processing from the bulk action page
-1. Filter the runs table to show the runs you want to cancel (e.g., all runs with status "QUEUED" or "EXECUTING")
-2. Use the checkboxes on the left side of the runs table to select the runs you want to cancel
-3. Click the "Cancel runs" button in the bulk action bar that appears at the bottom of the screen
+ You can replay or view the runs from this page
-After confirming, all selected runs that can be canceled (those in appropriate states like QUEUED or EXECUTING) will be canceled. The status of these runs will change to "CANCELED" and they will not be resumed.
+
You can only cancel runs that are in states that allow cancellation (like QUEUED or EXECUTING).
- Runs that are already completed, failed, or in other final states cannot be canceled.
+ Runs that are already completed, failed, or in other final states by the time the bulk action process gets to them, cannot be canceled.
\ No newline at end of file
diff --git a/docs/cli-preview-archive.mdx b/docs/cli-preview-archive.mdx
index 2f0fb81ad1..292742798e 100644
--- a/docs/cli-preview-archive.mdx
+++ b/docs/cli-preview-archive.mdx
@@ -2,10 +2,8 @@
title: "CLI preview archive command"
sidebarTitle: "preview archive"
description: "The `trigger.dev preview archive` command can be used to archive a preview branch."
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
import ProjectPathArg from "/snippets/cli-args-project-path.mdx";
import CommonOptions from "/snippets/cli-options-common.mdx";
import ProjectRefOption from "/snippets/cli-options-project-ref.mdx";
@@ -14,22 +12,20 @@ import ConfigFileOption from "/snippets/cli-options-config-file.mdx";
import SkipUpdateCheckOption from "/snippets/cli-options-skip-update-check.mdx";
import BranchOption from "/snippets/cli-options-branch.mdx";
-
-
Run the command like this:
```bash npm
-npx trigger.dev@v4-beta preview archive
+npx trigger.dev@latest preview archive
```
```bash pnpm
-pnpm dlx trigger.dev@v4-beta preview archive
+pnpm dlx trigger.dev@latest preview archive
```
```bash yarn
-yarn dlx trigger.dev@v4-beta preview archive
+yarn dlx trigger.dev@latest preview archive
```
@@ -39,7 +35,7 @@ It will archive the preview branch, automatically detecting the branch name from
## Arguments
```
-npx trigger.dev@v4-beta preview archive [path]
+npx trigger.dev@latest preview archive [path]
```
diff --git a/docs/cli-switch.mdx b/docs/cli-switch.mdx
index ac3f529348..40df6793a5 100644
--- a/docs/cli-switch.mdx
+++ b/docs/cli-switch.mdx
@@ -2,10 +2,8 @@
title: "CLI switch command"
sidebarTitle: "switch"
description: "The `trigger.dev switch` command can be used to switch between profiles."
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
import ProjectPathArg from "/snippets/cli-args-project-path.mdx";
import CommonOptions from "/snippets/cli-options-common.mdx";
import ProjectRefOption from "/snippets/cli-options-project-ref.mdx";
@@ -14,22 +12,20 @@ import ConfigFileOption from "/snippets/cli-options-config-file.mdx";
import SkipUpdateCheckOption from "/snippets/cli-options-skip-update-check.mdx";
import BranchOption from "/snippets/cli-options-branch.mdx";
-
-
Run the command like this:
```bash npm
-npx trigger.dev@v4-beta switch [profile]
+npx trigger.dev@latest switch [profile]
```
```bash pnpm
-pnpm dlx trigger.dev@v4-beta switch [profile]
+pnpm dlx trigger.dev@latest switch [profile]
```
```bash yarn
-yarn dlx trigger.dev@v4-beta switch [profile]
+yarn dlx trigger.dev@latest switch [profile]
```
@@ -39,7 +35,7 @@ It will switch to the specified profile. If no profile is specified, it will lis
## Arguments
```
-npx trigger.dev@v4-beta switch [profile]
+npx trigger.dev@latest switch [profile]
```
diff --git a/docs/config/config-file.mdx b/docs/config/config-file.mdx
index 5bf73a1a95..8389da1d02 100644
--- a/docs/config/config-file.mdx
+++ b/docs/config/config-file.mdx
@@ -11,7 +11,7 @@ import NodeVersions from "/snippets/node-versions.mdx";
The `trigger.config.ts` file is used to configure your Trigger.dev project. It is a TypeScript file at the root of your project that exports a default configuration object. Here's an example:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
// Your project ref (you can see it on the Project settings page in the dashboard)
@@ -53,7 +53,7 @@ The config file handles a lot of things, like:
You can specify the directories where your tasks are located using the `dirs` option:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -66,7 +66,7 @@ If you omit the `dirs` option, we will automatically detect directories that are
We will search for TypeScript and JavaScript files in the specified directories and include them in the build process. We automatically exclude files that have `.test` or `.spec` in the name, but you can customize this by specifying glob patterns in the `ignorePatterns` option:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -80,7 +80,7 @@ export default defineConfig({
You can add lifecycle functions to get notified when any task starts, succeeds, or fails using `onStart`, `onSuccess` and `onFailure`:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -111,7 +111,7 @@ We use OpenTelemetry (OTEL) for our run logs. This means you get a lot of inform
Here we add Prisma and OpenAI instrumentations to your `trigger.config.ts` file.
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { PrismaInstrumentation } from "@prisma/instrumentation";
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
@@ -152,7 +152,7 @@ You can also configure custom telemetry exporters to send your traces and logs t
Then, configure the exporters in your `trigger.config.ts` file:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
@@ -188,15 +188,10 @@ export default defineConfig({
Make sure to set the `AXIOM_API_TOKEN` and `AXIOM_DATASET` environment variables in your project.
-
- The `logExporters` option is available in the v4 beta SDK. See our [v4 upgrade
- guide](/upgrade-to-v4) for more information.
-
-
It's important to note that you cannot configure exporters using `OTEL_*` environment variables, as they would conflict with our internal telemetry. Instead you should configure the exporters via passing in arguments to the `OTLPTraceExporter` and `OTLPLogExporter` constructors. For example, here is how you can configure exporting to Honeycomb:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
@@ -235,7 +230,7 @@ export default defineConfig({
We currently only officially support the `node` runtime, but you can try our experimental `bun` runtime by setting the `runtime` option in your config file:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -255,7 +250,7 @@ See our [Bun guide](/guides/frameworks/bun) for more information.
You can specify the default machine for all tasks in your project:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -271,7 +266,7 @@ See our [machines documentation](/machines) for more information.
You can set the log level for your project:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -287,7 +282,7 @@ The `logLevel` only determines which logs are sent to the Trigger.dev instance w
You can set the default `maxDuration` for all tasks in your project:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -303,7 +298,7 @@ See our [maxDuration guide](/runs/max-duration) for more information.
You can customize the build process using the `build` option:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -326,7 +321,7 @@ export default defineConfig({
All code is bundled by default, but you can exclude some packages from the bundle using the `external` option:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -342,7 +337,7 @@ When a package is excluded from the bundle, it will be added to a dynamically ge
Each entry in the external should be a package name, not necessarily the import path. For example, if you want to exclude the `ai` package, but you are importing `ai/rsc`, you should just include `ai` in the `external` array:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -363,7 +358,7 @@ export default defineConfig({
You can customize the `jsx` options that are passed to `esbuild` using the `jsx` option:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -390,7 +385,7 @@ See the [esbuild JSX documentation](https://esbuild.github.io/content-types/#jsx
You can add custom [import conditions](https://esbuild.github.io/api/#conditions) to your build using the `conditions` option:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
diff --git a/docs/config/extensions/additionalFiles.mdx b/docs/config/extensions/additionalFiles.mdx
index 455459a82c..58677914d4 100644
--- a/docs/config/extensions/additionalFiles.mdx
+++ b/docs/config/extensions/additionalFiles.mdx
@@ -7,7 +7,7 @@ description: "Use the additionalFiles build extension to copy additional files t
Import the `additionalFiles` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { additionalFiles } from "@trigger.dev/build/extensions/core";
export default defineConfig({
diff --git a/docs/config/extensions/additionalPackages.mdx b/docs/config/extensions/additionalPackages.mdx
index 7837c5dacd..d62562e670 100644
--- a/docs/config/extensions/additionalPackages.mdx
+++ b/docs/config/extensions/additionalPackages.mdx
@@ -7,7 +7,7 @@ description: "Use the additionalPackages build extension to include additional p
Import the `additionalPackages` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { additionalPackages } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -22,7 +22,7 @@ export default defineConfig({
This allows you to include additional packages in the build that are not automatically included via imports. This is useful if you want to install a package that includes a CLI tool that you want to invoke in your tasks via `exec`. We will try to automatically resolve the version of the package but you can specify the version by using the `@` symbol:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
diff --git a/docs/config/extensions/aptGet.mdx b/docs/config/extensions/aptGet.mdx
index b45ecaa485..817c4157d7 100644
--- a/docs/config/extensions/aptGet.mdx
+++ b/docs/config/extensions/aptGet.mdx
@@ -7,7 +7,7 @@ description: "Use the aptGet build extension to install system packages into the
You can install system packages into the deployed image using the `aptGet` extension:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { aptGet } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -22,7 +22,7 @@ export default defineConfig({
If you want to install a specific version of a package, you can specify the version like this:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
diff --git a/docs/config/extensions/audioWaveform.mdx b/docs/config/extensions/audioWaveform.mdx
index 7b3df9f3da..de23eb0476 100644
--- a/docs/config/extensions/audioWaveform.mdx
+++ b/docs/config/extensions/audioWaveform.mdx
@@ -7,7 +7,7 @@ description: "Use the audioWaveform build extension to add support for Audio Wav
Previously, we installed [Audio Waveform](https://github.com/bbc/audiowaveform) in the build image. That's been moved to a build extension:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { audioWaveform } from "@trigger.dev/build/extensions/audioWaveform";
export default defineConfig({
diff --git a/docs/config/extensions/custom.mdx b/docs/config/extensions/custom.mdx
index 2d581c6545..02c5980cf9 100644
--- a/docs/config/extensions/custom.mdx
+++ b/docs/config/extensions/custom.mdx
@@ -20,7 +20,7 @@ Build extensions allow you to hook into the build system and customize the build
Build extensions are added to your `trigger.config.ts` file, with a required `name` and optional build hook functions. Here's a simple example of a build extension that just logs a message when the build starts:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "my-project",
@@ -45,7 +45,7 @@ You can also extract that out into a function instead of defining it inline, in
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { BuildExtension } from "@trigger.dev/build";
export default defineConfig({
@@ -72,7 +72,7 @@ function myExtension(): BuildExtension {
This allows the extension to add additional dependencies to the list of externals for the build. This is useful for dependencies that are not included in the bundle, but are expected to be available at runtime.
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "my-project",
@@ -94,7 +94,7 @@ export default defineConfig({
This hook runs before the build starts. It receives the `BuildContext` object as an argument.
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "my-project",
@@ -114,7 +114,7 @@ export default defineConfig({
If you want to add an esbuild plugin, you must do so in the `onBuildStart` hook. Here's an example of adding a custom esbuild plugin:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "my-project",
@@ -144,7 +144,7 @@ export default defineConfig({
You can use the `BuildContext.target` property to determine if the build is for `dev` or `deploy`:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "my-project",
@@ -170,7 +170,7 @@ export default defineConfig({
This hook runs after the build completes. It receives the `BuildContext` object and a `BuildManifest` object as arguments. This is where you can add in one or more `BuildLayer`'s to the context.
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "my-project",
diff --git a/docs/config/extensions/emitDecoratorMetadata.mdx b/docs/config/extensions/emitDecoratorMetadata.mdx
index 49f5d399b7..24317fae5d 100644
--- a/docs/config/extensions/emitDecoratorMetadata.mdx
+++ b/docs/config/extensions/emitDecoratorMetadata.mdx
@@ -7,7 +7,7 @@ description: "Use the emitDecoratorMetadata build extension to enable support fo
If you need support for the `emitDecoratorMetadata` typescript compiler option, import the `emitDecoratorMetadata` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { emitDecoratorMetadata } from "@trigger.dev/build/extensions/typescript";
export default defineConfig({
diff --git a/docs/config/extensions/esbuildPlugin.mdx b/docs/config/extensions/esbuildPlugin.mdx
index bc0a7fc87b..71f5a1ac1e 100644
--- a/docs/config/extensions/esbuildPlugin.mdx
+++ b/docs/config/extensions/esbuildPlugin.mdx
@@ -7,7 +7,7 @@ description: "Use the esbuildPlugin build extension to add existing or custom es
You can easily add existing or custom esbuild plugins to your build process using the `esbuildPlugin` extension:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { esbuildPlugin } from "@trigger.dev/build/extensions";
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";
diff --git a/docs/config/extensions/ffmpeg.mdx b/docs/config/extensions/ffmpeg.mdx
index 581970b411..cd414c4af5 100644
--- a/docs/config/extensions/ffmpeg.mdx
+++ b/docs/config/extensions/ffmpeg.mdx
@@ -7,7 +7,7 @@ description: "Use the ffmpeg build extension to include FFmpeg in your project"
You can add the `ffmpeg` build extension to your build process:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { ffmpeg } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -26,7 +26,7 @@ By default, this will install the version of `ffmpeg` that is available in the D
If you need FFmpeg 7.x, you can pass `{ version: "7" }` to the extension. This will install a static build of FFmpeg 7.x instead of using the Debian package:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { ffmpeg } from "@trigger.dev/build/extensions/core";
export default defineConfig({
diff --git a/docs/config/extensions/overview.mdx b/docs/config/extensions/overview.mdx
index abba56694e..4cb07bc659 100644
--- a/docs/config/extensions/overview.mdx
+++ b/docs/config/extensions/overview.mdx
@@ -11,7 +11,7 @@ You can use pre-built extensions by installing the `@trigger.dev/build` package
Build extensions are added to your `trigger.config.ts` file under the `build.extensions` property:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "my-project",
@@ -31,7 +31,7 @@ export default defineConfig({
If you are using a pre-built extension, you can import it from the `@trigger.dev/build` package:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { ffmpeg } from "@trigger.dev/build/extensions/core";
export default defineConfig({
diff --git a/docs/config/extensions/playwright.mdx b/docs/config/extensions/playwright.mdx
index 0a6dce2bf5..db9ad34257 100644
--- a/docs/config/extensions/playwright.mdx
+++ b/docs/config/extensions/playwright.mdx
@@ -2,13 +2,8 @@
title: "Playwright"
sidebarTitle: "playwright"
description: "Use the playwright build extension to use Playwright with Trigger.dev"
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
-
-
-
If you are using [Playwright](https://playwright.dev/), you should use the Playwright build extension.
- Automatically installs Playwright and required browser dependencies
@@ -24,7 +19,7 @@ If you are using [Playwright](https://playwright.dev/), you should use the Playw
You can use it for a simple Playwright setup like this:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { playwright } from "@trigger.dev/build/extensions/playwright";
export default defineConfig({
@@ -51,7 +46,7 @@ export default defineConfig({
### Custom browsers and version
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { playwright } from "@trigger.dev/build/extensions/playwright";
export default defineConfig({
@@ -72,7 +67,7 @@ export default defineConfig({
By default, browsers are run in headless mode. If you need to run browsers with a UI (for example, for debugging), set `headless: false`. This will automatically set up a virtual display using Xvfb.
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { playwright } from "@trigger.dev/build/extensions/playwright";
export default defineConfig({
diff --git a/docs/config/extensions/prismaExtension.mdx b/docs/config/extensions/prismaExtension.mdx
index 73bc94b16a..2d057cc264 100644
--- a/docs/config/extensions/prismaExtension.mdx
+++ b/docs/config/extensions/prismaExtension.mdx
@@ -16,7 +16,7 @@ If you are using Prisma, you should use the prisma build extension.
You can use it for a simple Prisma setup like this:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -43,7 +43,7 @@ export default defineConfig({
If you want to also run migrations during the build process, you can pass in the `migrate` option:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -92,7 +92,7 @@ generator json {
```
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -116,7 +116,7 @@ export default defineConfig({
If you are using [TypedSQL](https://www.prisma.io/typedsql), you'll need to enable it via the `typedSql` option:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
diff --git a/docs/config/extensions/puppeteer.mdx b/docs/config/extensions/puppeteer.mdx
index 62942e7f87..a2f3091bd7 100644
--- a/docs/config/extensions/puppeteer.mdx
+++ b/docs/config/extensions/puppeteer.mdx
@@ -9,7 +9,7 @@ description: "Use the puppeteer build extension to enable support for Puppeteer
To use Puppeteer in your project, add these build settings to your `trigger.config.ts` file:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { puppeteer } from "@trigger.dev/build/extensions/puppeteer";
export default defineConfig({
diff --git a/docs/config/extensions/pythonExtension.mdx b/docs/config/extensions/pythonExtension.mdx
index 21704d65d3..a8a30a02fb 100644
--- a/docs/config/extensions/pythonExtension.mdx
+++ b/docs/config/extensions/pythonExtension.mdx
@@ -15,7 +15,7 @@ npm add @trigger.dev/python
Then, you can use the `pythonExtension` build extension in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { pythonExtension } from "@trigger.dev/python/extension";
export default defineConfig({
@@ -29,7 +29,7 @@ export default defineConfig({
This will take care of adding python to the build image and setting up the necessary environment variables to execute Python scripts. You can then use our `python` utilities in the `@trigger.dev/python` package to execute Python scripts in your tasks. For example, running a Python script inline in a task:
```ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { python } from "@trigger.dev/python";
export const myScript = task({
@@ -46,7 +46,7 @@ export const myScript = task({
You can automatically add python scripts to your project using the `scripts` option in the `pythonExtension` function. This will copy the specified scripts to the build directory during the deploy process. For example:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { pythonExtension } from "@trigger.dev/python/extension";
export default defineConfig({
@@ -64,7 +64,7 @@ export default defineConfig({
This will copy all Python files in the `python` directory to the build directory during the deploy process. You can then execute these scripts using the `python.runScript` function:
```ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { python } from "@trigger.dev/python";
export const myScript = task({
@@ -86,7 +86,7 @@ export const myScript = task({
If you have a `requirements.txt` file in your project, you can use the `requirementsFile` option in the `pythonExtension` function to install the required packages during the build process. For example:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { pythonExtension } from "@trigger.dev/python/extension";
export default defineConfig({
@@ -113,7 +113,7 @@ This will install the packages specified in the `requirements.txt` file during t
If you are using a virtual environment in your project, you can use the `devPythonBinaryPath` option in the `pythonExtension` function to specify the path to the Python binary in the virtual environment. For example:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { pythonExtension } from "@trigger.dev/python/extension";
export default defineConfig({
@@ -135,7 +135,7 @@ This has no effect in production mode, but in development mode, it will use the
All of the `python` functions have a streaming version that allows you to stream the output of the Python script as it runs. For example:
```ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { python } from "@trigger.dev/python";
export const myStreamingScript = task({
@@ -165,7 +165,7 @@ print(os.environ["MY_ENV_VAR"])
You can also pass additional environment variables to the Python script using the `env` option in the `python.runScript` function. For example:
```ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { python } from "@trigger.dev/python";
export const myScript = task({
diff --git a/docs/config/extensions/syncEnvVars.mdx b/docs/config/extensions/syncEnvVars.mdx
index c4fc338fec..6241e1f520 100644
--- a/docs/config/extensions/syncEnvVars.mdx
+++ b/docs/config/extensions/syncEnvVars.mdx
@@ -9,7 +9,7 @@ The `syncEnvVars` build extension will sync env vars from another service into T
`syncEnvVars` takes an async callback function, and any env vars returned from the callback will be synced to Trigger.dev.
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncEnvVars } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -37,7 +37,7 @@ The callback is passed a context object with the following properties:
In this example we're using env vars from [Infisical](https://infisical.com).
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncEnvVars } from "@trigger.dev/build/extensions/core";
import { InfisicalSDK } from "@infisical/sdk";
@@ -81,7 +81,7 @@ The `syncVercelEnvVars` build extension syncs environment variables from your Ve
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncVercelEnvVars } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -97,7 +97,7 @@ export default defineConfig({
Or you can pass in the token and project ID as arguments:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncVercelEnvVars } from "@trigger.dev/build/extensions/core";
export default defineConfig({
diff --git a/docs/context.mdx b/docs/context.mdx
index bd9d3547ed..4e4b8f7bac 100644
--- a/docs/context.mdx
+++ b/docs/context.mdx
@@ -13,7 +13,7 @@ Context (`ctx`) is a way to get information about a run.
```typescript Context example
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const parentTask = task({
id: "parent-task",
diff --git a/docs/deploy-environment-variables.mdx b/docs/deploy-environment-variables.mdx
index 3815c106be..f9e447036f 100644
--- a/docs/deploy-environment-variables.mdx
+++ b/docs/deploy-environment-variables.mdx
@@ -95,7 +95,7 @@ You could use the SDK functions above but it's much easier to use our `syncEnvVa
In this example we're using env vars from [Infisical](https://infisical.com).
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncEnvVars } from "@trigger.dev/build/extensions/core";
import { InfisicalSDK } from "@infisical/sdk";
diff --git a/docs/deployment/overview.mdx b/docs/deployment/overview.mdx
index d2c3b7e7e3..e52b2dc58a 100644
--- a/docs/deployment/overview.mdx
+++ b/docs/deployment/overview.mdx
@@ -223,7 +223,7 @@ Usually there will be some useful guidance below this message. If you can't figu
This happens because `.node` files are native code and can't be bundled like other packages. To fix this, add your package to [`build.external`](/config/config-file#external) in the `trigger.config.ts` file like this:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
diff --git a/docs/deployment/preview-branches.mdx b/docs/deployment/preview-branches.mdx
index f7882970df..7e98e51287 100644
--- a/docs/deployment/preview-branches.mdx
+++ b/docs/deployment/preview-branches.mdx
@@ -1,13 +1,8 @@
---
title: "Preview branches"
description: "Create isolated environments for each branch of your code, allowing you to test changes before merging to production. You can create preview branches manually or automatically from your git branches."
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
-
-
-
## How to use preview branches
The preview environment is special – you create branches from it. The branches you create live under the preview environment and have all the features you're used to from other environments (like staging or production). That means you can trigger runs, have schedules, test them, use Realtime, etc.
@@ -101,7 +96,7 @@ jobs:
run: npm install
- name: Deploy preview branch
- run: npx trigger.dev@v4-beta deploy --env preview
+ run: npx trigger.dev@latest deploy --env preview
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
```
@@ -121,13 +116,13 @@ You can manually specify the branch using `--branch ` in the deploy
Creating and deploying a preview branch manually is easy:
```bash
-npx trigger.dev@v4-beta deploy --env preview
+npx trigger.dev@latest deploy --env preview
```
This will create and deploy a preview branch, automatically detecting the git branch. If for some reason the auto-detection doesn't work it will let you know and tell you do this:
```bash
-npx trigger.dev@v4-beta deploy --env preview --branch your-branch-name
+npx trigger.dev@latest deploy --env preview --branch your-branch-name
```
### Archiving a preview branch
@@ -135,7 +130,7 @@ npx trigger.dev@v4-beta deploy --env preview --branch your-branch-name
You can manually archive a preview branch with the CLI:
```bash
-npx trigger.dev@v4-beta preview archive
+npx trigger.dev@latest preview archive
```
Again we will try auto-detect the current branch. But you can specify the branch name with `--branch `.
diff --git a/docs/docs.json b/docs/docs.json
index b88d903a93..9006ab10a7 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -27,7 +27,7 @@
"video-walkthrough",
"how-it-works",
"limits",
- "upgrade-to-v4"
+ "migrating-from-v3"
]
},
{
@@ -60,7 +60,9 @@
"tags",
"runs/metadata",
"run-usage",
- "context"
+ "context",
+ "runs/priority",
+ "hidden-tasks"
]
},
{
@@ -120,7 +122,8 @@
"pages": [
"frontend/react-hooks/overview",
"frontend/react-hooks/realtime",
- "frontend/react-hooks/triggering"
+ "frontend/react-hooks/triggering",
+ "frontend/react-hooks/use-wait-token"
]
}
]
@@ -182,15 +185,11 @@
{
"group": "Environment variables",
"pages": ["self-hosting/env/webapp", "self-hosting/env/supervisor"]
- }
- ],
- "tags": ["v4"],
- "tag": "v4"
- },
- {
- "group": "Self-hosting",
- "pages": ["open-source-self-hosting"]
+ },
+ "open-source-self-hosting"
+ ]
},
+
{
"group": "Open source",
"pages": ["open-source-contributing", "github-repo", "changelog", "roadmap"]
@@ -575,6 +574,10 @@
{
"source": "/management/projects/runs",
"destination": "/management/overview"
+ },
+ {
+ "source": "/upgrade-to-v4",
+ "destination": "/migrating-from-v3"
}
]
}
diff --git a/docs/errors-retrying.mdx b/docs/errors-retrying.mdx
index 2a9fd3863b..7bd2deae3c 100644
--- a/docs/errors-retrying.mdx
+++ b/docs/errors-retrying.mdx
@@ -31,7 +31,7 @@ This task will retry 10 times with exponential backoff.
One way to gain reliability is to break your work into smaller tasks and [trigger](/triggering) them from each other. Each task can have its own retrying behavior:
```ts /trigger/multiple-tasks.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -70,7 +70,7 @@ We provide some useful functions that you can use to retry smaller parts of a ta
You can retry a block of code that can throw an error, with the same retry settings as a task.
```ts /trigger/retry-on-throw.ts
-import { task, logger, retry } from "@trigger.dev/sdk/v3";
+import { task, logger, retry } from "@trigger.dev/sdk";
export const retryOnThrow = task({
id: "retry-on-throw",
@@ -106,7 +106,7 @@ You can use `fetch`, `axios`, or any other library in your code.
But we do provide a convenient function to perform HTTP requests with conditional retrying based on the response:
```ts /trigger/retry-fetch.ts
-import { task, logger, retry } from "@trigger.dev/sdk/v3";
+import { task, logger, retry } from "@trigger.dev/sdk";
export const taskWithFetchRetries = task({
id: "task-with-fetch-retries",
@@ -203,7 +203,7 @@ In this complicated example:
```ts tasks.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { calculateISO8601DurationOpenAIVariantResetAt, openai } from "./openai.js";
export const openaiTask = task({
@@ -309,7 +309,7 @@ export function calculateISO8601DurationOpenAIVariantResetAt(
You can prevent retries by throwing an `AbortTaskRunError`. This will fail the task attempt and disable retrying.
```ts /trigger/myTasks.ts
-import { task, AbortTaskRunError } from "@trigger.dev/sdk/v3";
+import { task, AbortTaskRunError } from "@trigger.dev/sdk";
export const openaiTask = task({
id: "openai-task",
@@ -335,7 +335,7 @@ export const openaiTask = task({
Sometimes you want to catch an error and don't want to retry the task. You can use try/catch as you normally would. In this example we fallback to using Replicate if OpenAI fails.
```ts /trigger/myTasks.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const openaiTask = task({
id: "openai-task",
diff --git a/docs/frontend/overview.mdx b/docs/frontend/overview.mdx
index 6df411bc3a..9352e229aa 100644
--- a/docs/frontend/overview.mdx
+++ b/docs/frontend/overview.mdx
@@ -11,7 +11,7 @@ You can use our [React hooks](/frontend/react-hooks) in your frontend applicatio
To create a Public Access Token, you can use the `auth.createPublicToken` function in your **backend** code:
```tsx
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken(); // 👈 this public access token has no permissions, so is pretty useless!
```
@@ -21,7 +21,7 @@ const publicToken = await auth.createPublicToken(); // 👈 this public access t
By default a Public Access Token has no permissions. You must specify the scopes you need when creating a Public Access Token:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken({
scopes: {
@@ -35,7 +35,7 @@ const publicToken = await auth.createPublicToken({
This will allow the token to read all runs, which is probably not what you want. You can specify only certain runs by passing an array of run IDs:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken({
scopes: {
@@ -49,7 +49,7 @@ const publicToken = await auth.createPublicToken({
You can scope the token to only read certain tasks:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken({
scopes: {
@@ -63,7 +63,7 @@ const publicToken = await auth.createPublicToken({
Or tags:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken({
scopes: {
@@ -77,7 +77,7 @@ const publicToken = await auth.createPublicToken({
Or a specific batch of runs:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken({
scopes: {
@@ -91,7 +91,7 @@ const publicToken = await auth.createPublicToken({
You can also combine scopes. For example, to read runs with specific tags and for specific tasks:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken({
scopes: {
@@ -108,7 +108,7 @@ const publicToken = await auth.createPublicToken({
By default, Public Access Token's expire after 15 minutes. You can specify a different expiration time when creating a Public Access Token:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
const publicToken = await auth.createPublicToken({
expirationTime: "1hr",
@@ -126,7 +126,7 @@ The format used for a time span is the same as the [jose package](https://github
When triggering a task from your backend, the `handle` received from the `trigger` function now includes a `publicAccessToken` field. This token can be used to authenticate requests in your frontend application:
```ts
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
const handle = await tasks.trigger("my-task", { some: "data" });
@@ -136,7 +136,7 @@ console.log(handle.publicAccessToken);
By default, tokens returned from the `trigger` function expire after 15 minutes and have a read scope for that specific run. You can customize the expiration of the auto-generated tokens by passing a `publicTokenOptions` object to the `trigger` function:
```ts
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
const handle = await tasks.trigger(
"my-task",
@@ -155,7 +155,7 @@ const handle = await tasks.trigger(
You will also get back a Public Access Token when using the `batchTrigger` function:
```ts
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
const handle = await tasks.batchTrigger("my-task", [
{ payload: { some: "data" } },
diff --git a/docs/frontend/react-hooks/overview.mdx b/docs/frontend/react-hooks/overview.mdx
index 3dedfcaa2b..8c856f66d8 100644
--- a/docs/frontend/react-hooks/overview.mdx
+++ b/docs/frontend/react-hooks/overview.mdx
@@ -137,7 +137,7 @@ If you are using Next.js with the App Router and you are triggering a task from
```tsx actions/trigger.ts
"use server";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { exampleTask } from "@/trigger/example";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
@@ -171,7 +171,7 @@ export default function RunPage({ params }: { params: { id: string } }) {
Instead of a cookie, you could also use a query parameter to pass the token to the frontend:
```tsx actions/trigger.ts
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { exampleTask } from "@/trigger/example";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
@@ -224,7 +224,7 @@ export default async function RunPage({ params }: { params: { id: string } }) {
```
```tsx trigger/auth.ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
export async function generatePublicAccessToken(runId: string) {
return auth.createPublicToken({
@@ -334,4 +334,8 @@ See our [Realtime hooks documentation](/frontend/react-hooks/realtime) for more
See our [Trigger hooks documentation](/frontend/react-hooks/triggering) for more information.
+## useWaitToken
+
+See our [useWaitToken documentation](/frontend/react-hooks/use-wait-token) for more information.
+
diff --git a/docs/frontend/react-hooks/triggering.mdx b/docs/frontend/react-hooks/triggering.mdx
index 26bfcb1c12..52b88ae79c 100644
--- a/docs/frontend/react-hooks/triggering.mdx
+++ b/docs/frontend/react-hooks/triggering.mdx
@@ -37,7 +37,7 @@ yarn install @trigger.dev/react-hooks
To authenticate a trigger hook, you must provide a special one-time use "trigger" token. These tokens are very similar to [Public Access Tokens](/frontend/overview#authentication), but they can only be used once to trigger a task. You can generate a trigger token using the `auth.createTriggerPublicToken` function in your backend code:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
// Somewhere in your backend code
const triggerToken = await auth.createTriggerPublicToken("my-task");
```
@@ -45,7 +45,7 @@ const triggerToken = await auth.createTriggerPublicToken("my-task");
These tokens also expire, with the default expiration time being 15 minutes. You can specify a custom expiration time by passing a `expirationTime` parameter:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
// Somewhere in your backend code
const triggerToken = await auth.createTriggerPublicToken("my-task", {
expirationTime: "24hr",
@@ -55,7 +55,7 @@ const triggerToken = await auth.createTriggerPublicToken("my-task", {
You can also pass multiple tasks to the `createTriggerPublicToken` function to create a token that can trigger multiple tasks:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
// Somewhere in your backend code
const triggerToken = await auth.createTriggerPublicToken(["my-task-1", "my-task-2"]);
```
@@ -63,7 +63,7 @@ const triggerToken = await auth.createTriggerPublicToken(["my-task-1", "my-task-
You can also pass the `multipleUse` parameter to create a token that can be used multiple times:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
// Somewhere in your backend code
const triggerToken = await auth.createTriggerPublicToken("my-task", {
diff --git a/docs/frontend/react-hooks/use-wait-token.mdx b/docs/frontend/react-hooks/use-wait-token.mdx
new file mode 100644
index 0000000000..03c4efc345
--- /dev/null
+++ b/docs/frontend/react-hooks/use-wait-token.mdx
@@ -0,0 +1,35 @@
+---
+title: "useWaitToken"
+sidebarTitle: "useWaitToken"
+description: "Use the useWaitToken hook to complete a wait token from a React component."
+---
+
+We've added a new `useWaitToken` react hook that allows you to complete a wait token from a React component, using a Public Access Token.
+
+```ts backend.ts
+import { wait } from "@trigger.dev/sdk";
+
+// Somewhere in your code, you'll need to create the token and then pass the token ID and the public token to the frontend
+const token = await wait.createToken({
+ timeout: "10m",
+});
+
+return {
+ tokenId: token.id,
+ publicToken: token.publicAccessToken, // An automatically generated public access token that expires in 1 hour
+};
+```
+
+Now you can use the `useWaitToken` hook in your frontend code:
+
+```tsx frontend.tsx
+import { useWaitToken } from "@trigger.dev/react-hooks";
+
+export function MyComponent({ publicToken, tokenId }: { publicToken: string; tokenId: string }) {
+ const { complete } = useWaitToken(tokenId, {
+ accessToken: publicToken,
+ });
+
+ return ;
+}
+```
\ No newline at end of file
diff --git a/docs/guides/ai-agents/generate-translate-copy.mdx b/docs/guides/ai-agents/generate-translate-copy.mdx
index 4d555f10a2..cb5e034aa3 100644
--- a/docs/guides/ai-agents/generate-translate-copy.mdx
+++ b/docs/guides/ai-agents/generate-translate-copy.mdx
@@ -24,7 +24,7 @@ In this example, we'll create a workflow that generates and translates copy. Thi
```typescript
import { openai } from "@ai-sdk/openai";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { generateText } from "ai";
export interface TranslatePayload {
diff --git a/docs/guides/ai-agents/respond-and-check-content.mdx b/docs/guides/ai-agents/respond-and-check-content.mdx
index ca487fa3dd..560b69b80c 100644
--- a/docs/guides/ai-agents/respond-and-check-content.mdx
+++ b/docs/guides/ai-agents/respond-and-check-content.mdx
@@ -23,7 +23,7 @@ In this example, we'll create a workflow that simultaneously checks content for
```typescript
import { openai } from "@ai-sdk/openai";
-import { batch, task } from "@trigger.dev/sdk/v3";
+import { batch, task } from "@trigger.dev/sdk";
import { generateText } from "ai";
// Task to generate customer response
diff --git a/docs/guides/ai-agents/route-question.mdx b/docs/guides/ai-agents/route-question.mdx
index 69eb705314..de1cb3e92f 100644
--- a/docs/guides/ai-agents/route-question.mdx
+++ b/docs/guides/ai-agents/route-question.mdx
@@ -24,7 +24,7 @@ In this example, we'll create a workflow that routes a question to a different A
```typescript
import { openai } from "@ai-sdk/openai";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { generateText } from "ai";
import { z } from "zod";
diff --git a/docs/guides/ai-agents/translate-and-refine.mdx b/docs/guides/ai-agents/translate-and-refine.mdx
index fd3d1b5a9d..80f557fd0c 100644
--- a/docs/guides/ai-agents/translate-and-refine.mdx
+++ b/docs/guides/ai-agents/translate-and-refine.mdx
@@ -23,7 +23,7 @@ This example task translates text into a target language and refines the transla
- Recursively calls itself to refine the translation based on the feedback
```typescript
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
diff --git a/docs/guides/ai-agents/verify-news-article.mdx b/docs/guides/ai-agents/verify-news-article.mdx
index 2d912c7415..e235ae9d35 100644
--- a/docs/guides/ai-agents/verify-news-article.mdx
+++ b/docs/guides/ai-agents/verify-news-article.mdx
@@ -26,7 +26,7 @@ Our example task uses multiple LLM calls to extract claims from a news article a
```typescript
import { openai } from "@ai-sdk/openai";
-import { batch, logger, task } from "@trigger.dev/sdk/v3";
+import { batch, logger, task } from "@trigger.dev/sdk";
import { CoreMessage, generateText } from "ai";
// Define types for our workers' outputs
diff --git a/docs/guides/example-projects/human-in-the-loop-workflow.mdx b/docs/guides/example-projects/human-in-the-loop-workflow.mdx
index 36d5bcc66f..6a8c82cadf 100644
--- a/docs/guides/example-projects/human-in-the-loop-workflow.mdx
+++ b/docs/guides/example-projects/human-in-the-loop-workflow.mdx
@@ -2,11 +2,8 @@
title: "Human-in-the-loop workflow with ReactFlow and Trigger.dev waitpoint tokens"
sidebarTitle: "Human-in-the-loop workflow"
description: "This example project creates audio summaries of newspaper articles using a human-in-the-loop workflow built with ReactFlow and Trigger.dev waitpoint tokens."
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
-
## Overview
This demo is a full stack example that uses the following:
@@ -77,9 +74,6 @@ await wait.completeToken(
);
```
-
-
-
While the workflow in this example is static and does not allow changing the connections between nodes in the UI, it serves as a good baseline for understanding how to build completely custom workflow builders using Trigger.dev and ReactFlow.
## Learn more about Trigger.dev Realtime and waitpoint tokens
diff --git a/docs/guides/example-projects/mastra-agents-with-memory.mdx b/docs/guides/example-projects/mastra-agents-with-memory.mdx
index b900d6df57..344eb7913c 100644
--- a/docs/guides/example-projects/mastra-agents-with-memory.mdx
+++ b/docs/guides/example-projects/mastra-agents-with-memory.mdx
@@ -2,13 +2,8 @@
title: "Mastra agents with memory sharing + Trigger.dev task orchestration"
sidebarTitle: "Mastra agents with memory"
description: "Multi-agent workflow with persistent memory sharing using Mastra and Trigger.dev for clothing recommendations based on weather data."
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
-
-
-
## Overview
Enter a city and an activity, and get a clothing recommendation generated for you based on today's weather.
diff --git a/docs/guides/example-projects/meme-generator-human-in-the-loop.mdx b/docs/guides/example-projects/meme-generator-human-in-the-loop.mdx
index bbf0aac412..050cfb543d 100644
--- a/docs/guides/example-projects/meme-generator-human-in-the-loop.mdx
+++ b/docs/guides/example-projects/meme-generator-human-in-the-loop.mdx
@@ -2,13 +2,8 @@
title: "Meme generator with human-in-the-loop approval"
sidebarTitle: "AI meme generator"
description: "This example project creates memes using OpenAI's DALL-E 3 with a human-in-the-loop approval workflow built using Trigger.dev waitpoint tokens."
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
-
-
-
## Overview
This demo is a full stack example that uses the following:
diff --git a/docs/guides/example-projects/openai-agents-sdk-typescript-playground.mdx b/docs/guides/example-projects/openai-agents-sdk-typescript-playground.mdx
index 531120204a..6ba17e539b 100644
--- a/docs/guides/example-projects/openai-agents-sdk-typescript-playground.mdx
+++ b/docs/guides/example-projects/openai-agents-sdk-typescript-playground.mdx
@@ -2,7 +2,6 @@
title: "OpenAI Agents SDK for Typescript + Trigger.dev playground"
sidebarTitle: "OpenAI Agents SDK for Typescript playground"
description: "Build production-ready AI agents with OpenAI Agents SDK for Typescript and Trigger.dev. Explore 7 examples covering streaming, multi-agent systems, and tool integration."
-tag: "v4"
---
## Overview
diff --git a/docs/guides/example-projects/vercel-ai-sdk-deep-research.mdx b/docs/guides/example-projects/vercel-ai-sdk-deep-research.mdx
index aa0d54687c..b267326c92 100644
--- a/docs/guides/example-projects/vercel-ai-sdk-deep-research.mdx
+++ b/docs/guides/example-projects/vercel-ai-sdk-deep-research.mdx
@@ -2,15 +2,10 @@
title: "Deep research agent using Vercel's AI SDK"
sidebarTitle: "Deep research agent"
description: "Deep research agent which generates comprehensive PDF reports using Vercel's AI SDK."
-tag: "v4"
---
import RealtimeLearnMore from "/snippets/realtime-learn-more.mdx";
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
-
-
-
Acknowledgements: This example project is derived from the brilliant [deep research
guide](https://aie-feb-25.vercel.app/docs/deep-research) by [Nico
diff --git a/docs/guides/examples/dall-e3-generate-image.mdx b/docs/guides/examples/dall-e3-generate-image.mdx
index 5846be703f..fc0a7f0d04 100644
--- a/docs/guides/examples/dall-e3-generate-image.mdx
+++ b/docs/guides/examples/dall-e3-generate-image.mdx
@@ -11,7 +11,7 @@ This example demonstrates how to use Trigger.dev to make reliable calls to AI AP
## Task code
```ts trigger/generateContent.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import OpenAI from "openai";
const openai = new OpenAI({
diff --git a/docs/guides/examples/deepgram-transcribe-audio.mdx b/docs/guides/examples/deepgram-transcribe-audio.mdx
index 90268e80bb..e9b43127bc 100644
--- a/docs/guides/examples/deepgram-transcribe-audio.mdx
+++ b/docs/guides/examples/deepgram-transcribe-audio.mdx
@@ -17,7 +17,7 @@ Transcribe audio using [Deepgram's](https://developers.deepgram.com/docs/introdu
```ts trigger/deepgramTranscription.ts
import { createClient } from "@deepgram/sdk";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
// Initialize the Deepgram client, using your Deepgram API key (you can find this in your Deepgram account settings).
const deepgram = createClient(process.env.DEEPGRAM_SECRET_KEY);
diff --git a/docs/guides/examples/fal-ai-image-to-cartoon.mdx b/docs/guides/examples/fal-ai-image-to-cartoon.mdx
index 1deb56b095..850a82b076 100644
--- a/docs/guides/examples/fal-ai-image-to-cartoon.mdx
+++ b/docs/guides/examples/fal-ai-image-to-cartoon.mdx
@@ -30,7 +30,7 @@ This video walks through the process of creating this task in a Next.js project.
This task converts an image to a cartoon using Fal.ai, and uploads the result to Cloudflare R2.
```ts trigger/fal-ai-image-to-cartoon.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import * as fal from "@fal-ai/serverless-client";
import fetch from "node-fetch";
diff --git a/docs/guides/examples/fal-ai-realtime.mdx b/docs/guides/examples/fal-ai-realtime.mdx
index 38f28c44f5..501c6ad814 100644
--- a/docs/guides/examples/fal-ai-realtime.mdx
+++ b/docs/guides/examples/fal-ai-realtime.mdx
@@ -41,7 +41,7 @@ This task generates an image from a prompt using Fal.ai.
```ts trigger/fal-ai-image-from-prompt-realtime.ts
import * as fal from "@fal-ai/serverless-client";
-import { logger, schemaTask } from "@trigger.dev/sdk/v3";
+import { logger, schemaTask } from "@trigger.dev/sdk";
import { z } from "zod";
export const FalResult = z.object({
diff --git a/docs/guides/examples/ffmpeg-video-processing.mdx b/docs/guides/examples/ffmpeg-video-processing.mdx
index 145545311b..260550c282 100644
--- a/docs/guides/examples/ffmpeg-video-processing.mdx
+++ b/docs/guides/examples/ffmpeg-video-processing.mdx
@@ -17,7 +17,7 @@ To use these example tasks, you'll first need to add our FFmpeg extension to you
```ts trigger.config.ts
import { ffmpeg } from "@trigger.dev/build/extensions/core";
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -52,7 +52,7 @@ This task demonstrates how to use FFmpeg to compress a video, reducing its file
```ts trigger/ffmpeg-compress-video.ts
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import ffmpeg from "fluent-ffmpeg";
import fs from "fs/promises";
import fetch from "node-fetch";
@@ -164,7 +164,7 @@ This task demonstrates how to use FFmpeg to extract audio from a video, convert
```ts trigger/ffmpeg-extract-audio.ts
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import ffmpeg from "fluent-ffmpeg";
import fs from "fs/promises";
import fetch from "node-fetch";
@@ -277,7 +277,7 @@ This task demonstrates how to use FFmpeg to generate a thumbnail from a video at
```ts trigger/ffmpeg-generate-thumbnail.ts
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import ffmpeg from "fluent-ffmpeg";
import fs from "fs/promises";
import fetch from "node-fetch";
diff --git a/docs/guides/examples/firecrawl-url-crawl.mdx b/docs/guides/examples/firecrawl-url-crawl.mdx
index b55b362693..61fcd98dfa 100644
--- a/docs/guides/examples/firecrawl-url-crawl.mdx
+++ b/docs/guides/examples/firecrawl-url-crawl.mdx
@@ -21,7 +21,7 @@ This task crawls a website and returns the `crawlResult` object. You can set the
```ts trigger/firecrawl-url-crawl.ts
import FirecrawlApp from "@mendable/firecrawl-js";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
// Initialize the Firecrawl client with your API key
const firecrawlClient = new FirecrawlApp({
@@ -66,7 +66,7 @@ This task scrapes a single URL and returns the `scrapeResult` object.
```ts trigger/firecrawl-url-scrape.ts
import FirecrawlApp, { ScrapeResponse } from "@mendable/firecrawl-js";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
// Initialize the Firecrawl client with your API key
const firecrawlClient = new FirecrawlApp({
diff --git a/docs/guides/examples/libreoffice-pdf-conversion.mdx b/docs/guides/examples/libreoffice-pdf-conversion.mdx
index 35d821834e..bec9f1e064 100644
--- a/docs/guides/examples/libreoffice-pdf-conversion.mdx
+++ b/docs/guides/examples/libreoffice-pdf-conversion.mdx
@@ -18,7 +18,7 @@ To deploy this task, you'll need to add LibreOffice to your project configuratio
```ts trigger.config.ts
import { aptGet } from "@trigger.dev/build/extensions/core";
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -55,7 +55,7 @@ This task demonstrates how to use LibreOffice to convert a document (.doc or .do
```ts trigger/libreoffice-pdf-convert.ts
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import libreoffice from "libreoffice-convert";
import { promisify } from "node:util";
import path from "path";
diff --git a/docs/guides/examples/open-ai-with-retrying.mdx b/docs/guides/examples/open-ai-with-retrying.mdx
index 2a0ae1f6be..483fbd9726 100644
--- a/docs/guides/examples/open-ai-with-retrying.mdx
+++ b/docs/guides/examples/open-ai-with-retrying.mdx
@@ -11,7 +11,7 @@ Sometimes OpenAI calls can take a long time to complete, or they can fail. This
## Task code
```ts trigger/openai.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import OpenAI from "openai";
const openai = new OpenAI({
diff --git a/docs/guides/examples/pdf-to-image.mdx b/docs/guides/examples/pdf-to-image.mdx
index 4c85264577..3a2a69f344 100644
--- a/docs/guides/examples/pdf-to-image.mdx
+++ b/docs/guides/examples/pdf-to-image.mdx
@@ -27,7 +27,7 @@ export default defineConfig({
## Task code
```ts trigger/pdfToImage.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { execSync } from "child_process";
import fs from "fs";
diff --git a/docs/guides/examples/puppeteer.mdx b/docs/guides/examples/puppeteer.mdx
index 7bd59db283..da1874476c 100644
--- a/docs/guides/examples/puppeteer.mdx
+++ b/docs/guides/examples/puppeteer.mdx
@@ -27,7 +27,7 @@ There are 3 example tasks to follow on this page:
To use all examples on this page, you'll first need to add these build settings to your `trigger.config.ts` file:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { puppeteer } from "@trigger.dev/build/extensions/puppeteer";
export default defineConfig({
@@ -59,7 +59,7 @@ In this example we use [Puppeteer](https://pptr.dev/) to log out the title of a
### Task code
```ts trigger/puppeteer-basic-example.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import puppeteer from "puppeteer";
export const puppeteerTask = task({
@@ -91,7 +91,7 @@ In this example we use [Puppeteer](https://pptr.dev/) to generate a PDF from the
### Task code
```ts trigger/puppeteer-generate-pdf.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import puppeteer from "puppeteer";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
@@ -158,7 +158,7 @@ In this example we use [Puppeteer](https://pptr.dev/) with a [BrowserBase](https
### Task code
```ts trigger/scrape-website.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import puppeteer from "puppeteer-core";
export const puppeteerScrapeWithProxy = task({
diff --git a/docs/guides/examples/react-email.mdx b/docs/guides/examples/react-email.mdx
index 4929fc373e..322b47da15 100644
--- a/docs/guides/examples/react-email.mdx
+++ b/docs/guides/examples/react-email.mdx
@@ -23,7 +23,7 @@ This example demonstrates how to use Trigger.dev to send emails using [React Ema
```tsx trigger/sendReactEmail.tsx
import { Body, Button, Container, Head, Heading, Html, Preview } from "@react-email/components";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import { Resend } from "resend";
// Initialize Resend client
@@ -293,7 +293,7 @@ const footer = {
And then to trigger the email, you can use the following task:
```tsx trigger/triggerWelcomeEmail.tsx
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import { Resend } from "resend";
import TriggerWelcomeEmail from "emails/trigger-welcome-email";
diff --git a/docs/guides/examples/react-pdf.mdx b/docs/guides/examples/react-pdf.mdx
index c766705999..dbffd155b3 100644
--- a/docs/guides/examples/react-pdf.mdx
+++ b/docs/guides/examples/react-pdf.mdx
@@ -13,7 +13,7 @@ This example demonstrates how to use Trigger.dev to generate a PDF using [react-
This example must be a .tsx file to use React components.
```ts trigger/generateResumePDF.tsx
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import { renderToBuffer, Document, Page, Text, View } from "@react-pdf/renderer";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
diff --git a/docs/guides/examples/satori.mdx b/docs/guides/examples/satori.mdx
index 62a386e20c..23052b0514 100644
--- a/docs/guides/examples/satori.mdx
+++ b/docs/guides/examples/satori.mdx
@@ -13,7 +13,7 @@ This can be customized and extended however you like, full list of options can b
## Task code
```tsx trigger/generateOgImage.ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { z } from "zod";
import satori from "satori";
import sharp from "sharp";
diff --git a/docs/guides/examples/scrape-hacker-news.mdx b/docs/guides/examples/scrape-hacker-news.mdx
index 69626ba1fc..fe9ecf1fd9 100644
--- a/docs/guides/examples/scrape-hacker-news.mdx
+++ b/docs/guides/examples/scrape-hacker-news.mdx
@@ -50,7 +50,7 @@ And we'll be using the following tools and features:
First up, add these build settings to your `trigger.config.ts` file:
```tsx trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { puppeteer } from "@trigger.dev/build/extensions/puppeteer";
export default defineConfig({
@@ -79,7 +79,7 @@ RESEND_API_KEY: ""
```ts trigger/scrape-hacker-news.ts
import { render } from "@react-email/render";
-import { logger, schedules, task, wait } from "@trigger.dev/sdk/v3";
+import { logger, schedules, task, wait } from "@trigger.dev/sdk";
import { OpenAI } from "openai";
import puppeteer from "puppeteer-core";
import { Resend } from "resend";
diff --git a/docs/guides/examples/sentry-error-tracking.mdx b/docs/guides/examples/sentry-error-tracking.mdx
index 735bb5f615..04eef6bf89 100644
--- a/docs/guides/examples/sentry-error-tracking.mdx
+++ b/docs/guides/examples/sentry-error-tracking.mdx
@@ -26,7 +26,7 @@ To send errors to Sentry when there are errors in your tasks, you'll need to add
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { esbuildPlugin } from "@trigger.dev/build/extensions";
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";
import * as Sentry from "@sentry/node";
@@ -80,7 +80,7 @@ To test that errors are being sent to Sentry, you need to create a task that wil
This task takes no payload, and will throw an error.
```ts trigger/sentry-error-test.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const sentryErrorTest = task({
id: "sentry-error-test",
diff --git a/docs/guides/examples/sharp-image-processing.mdx b/docs/guides/examples/sharp-image-processing.mdx
index becfc39c3c..890bb546ae 100644
--- a/docs/guides/examples/sharp-image-processing.mdx
+++ b/docs/guides/examples/sharp-image-processing.mdx
@@ -21,7 +21,7 @@ This task processes and watermarks an image using the Sharp library, and then up
To use this example, you'll first need to add these build settings to your `trigger.config.ts` file:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -49,7 +49,7 @@ export default defineConfig({
```ts trigger/sharp-image-processing.ts
import { S3Client } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import fs from "fs/promises";
import os from "os";
import path from "path";
diff --git a/docs/guides/examples/stripe-webhook.mdx b/docs/guides/examples/stripe-webhook.mdx
index 972ca3b7b9..b10c2b0280 100644
--- a/docs/guides/examples/stripe-webhook.mdx
+++ b/docs/guides/examples/stripe-webhook.mdx
@@ -32,7 +32,7 @@ Here are examples of how you can set up a handler using different frameworks:
```ts Next.js
// app/api/stripe-webhook/route.ts
import { NextResponse } from "next/server";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import Stripe from "stripe";
import type { stripeCheckoutCompleted } from "@/trigger/stripe-checkout-completed";
// 👆 **type-only** import
@@ -84,7 +84,7 @@ export async function POST(request: Request) {
import { type ActionFunctionArgs, json } from "@remix-run/node";
import type { stripeCheckoutCompleted } from "src/trigger/stripe-webhook";
// 👆 **type-only** import
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import Stripe from "stripe";
export async function action({ request }: ActionFunctionArgs) {
@@ -127,7 +127,7 @@ export async function action({ request }: ActionFunctionArgs) {
This task is triggered when a `checkout.session.completed` event is received from Stripe.
```ts trigger/stripe-checkout-completed.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import type stripe from "stripe";
export const stripeCheckoutCompleted = task({
diff --git a/docs/guides/examples/supabase-database-operations.mdx b/docs/guides/examples/supabase-database-operations.mdx
index 26796b7b0d..3cacbd2755 100644
--- a/docs/guides/examples/supabase-database-operations.mdx
+++ b/docs/guides/examples/supabase-database-operations.mdx
@@ -27,7 +27,7 @@ This is a basic task which inserts a new row into a table from a Trigger.dev tas
```ts trigger/supabase-database-insert.ts
import { createClient } from "@supabase/supabase-js";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import jwt from "jsonwebtoken";
// Generate the Typescript types using the Supabase CLI: https://supabase.com/docs/guides/api/rest/generating-types
import { Database } from "database.types";
@@ -117,7 +117,7 @@ This type of task is useful for managing user subscriptions, updating user detai
```ts trigger/supabase-update-user-subscription.ts
import { createClient } from "@supabase/supabase-js";
-import { AbortTaskRunError, task } from "@trigger.dev/sdk/v3";
+import { AbortTaskRunError, task } from "@trigger.dev/sdk";
// Generate the Typescript types using the Supabase CLI: https://supabase.com/docs/guides/api/rest/generating-types
import { Database } from "database.types";
diff --git a/docs/guides/examples/supabase-storage-upload.mdx b/docs/guides/examples/supabase-storage-upload.mdx
index a4c91d7e7c..d9b6544f40 100644
--- a/docs/guides/examples/supabase-storage-upload.mdx
+++ b/docs/guides/examples/supabase-storage-upload.mdx
@@ -22,7 +22,7 @@ This task downloads a video from a provided URL and uploads it to Supabase Stora
```ts trigger/supabase-storage-upload.ts
import { createClient } from "@supabase/supabase-js";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import fetch from "node-fetch";
// Initialize Supabase client
@@ -92,7 +92,7 @@ This task downloads a video from a provided URL, saves it to a temporary file, a
```ts trigger/supabase-storage-upload-s3.ts
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import fetch from "node-fetch";
// Initialize S3 client for Supabase Storage
diff --git a/docs/guides/examples/vercel-ai-sdk.mdx b/docs/guides/examples/vercel-ai-sdk.mdx
index db4f7306a5..dbddb8a6d6 100644
--- a/docs/guides/examples/vercel-ai-sdk.mdx
+++ b/docs/guides/examples/vercel-ai-sdk.mdx
@@ -19,7 +19,7 @@ This task shows how to use the Vercel AI SDK to generate text from a prompt with
### Task code
```ts trigger/vercel-ai-sdk-openai.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import { generateText } from "ai";
// Install the package of the AI model you want to use, in this case OpenAI
import { openai } from "@ai-sdk/openai"; // Ensure OPENAI_API_KEY environment variable is set
diff --git a/docs/guides/examples/vercel-sync-env-vars.mdx b/docs/guides/examples/vercel-sync-env-vars.mdx
index 59f72ea7e7..1397f6ccd3 100644
--- a/docs/guides/examples/vercel-sync-env-vars.mdx
+++ b/docs/guides/examples/vercel-sync-env-vars.mdx
@@ -20,7 +20,7 @@ To sync environment variables, you just need to add our build extension to your
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncVercelEnvVars } from "@trigger.dev/build/extensions/core";
export default defineConfig({
diff --git a/docs/guides/frameworks/bun.mdx b/docs/guides/frameworks/bun.mdx
index 380ebcdc1d..0d369fbf98 100644
--- a/docs/guides/frameworks/bun.mdx
+++ b/docs/guides/frameworks/bun.mdx
@@ -62,7 +62,7 @@ Install the "Hello World" example task when prompted. We'll use this task to tes
```ts example.ts
import { Database } from "bun:sqlite";
- import { task } from "@trigger.dev/sdk/v3";
+ import { task } from "@trigger.dev/sdk";
export const bunTask = task({
id: "bun-task",
diff --git a/docs/guides/frameworks/drizzle.mdx b/docs/guides/frameworks/drizzle.mdx
index 81a4868828..5ea84d9e10 100644
--- a/docs/guides/frameworks/drizzle.mdx
+++ b/docs/guides/frameworks/drizzle.mdx
@@ -51,7 +51,7 @@ This is a simple task that will add a new user to your database, we will call it
```ts /trigger/drizzle-add-new-user.ts
import { eq } from "drizzle-orm";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { users } from "src/db/schema";
import { drizzle } from "drizzle-orm/node-postgres";
@@ -80,7 +80,7 @@ Next, in your `trigger.config.js` file, add `pg` to the `externals` array. `pg`
It is marked as an external to ensure that it is not bundled into the task's bundle, and instead will be installed and loaded from `node_modules` at runtime.
```js /trigger.config.js
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "", // Your project reference
diff --git a/docs/guides/frameworks/nextjs-webhooks.mdx b/docs/guides/frameworks/nextjs-webhooks.mdx
index 5f7d6de036..25c91f0726 100644
--- a/docs/guides/frameworks/nextjs-webhooks.mdx
+++ b/docs/guides/frameworks/nextjs-webhooks.mdx
@@ -36,7 +36,7 @@ In your new file, add the following code:
```ts /pages/api/webhook-handler.ts
import { helloWorldTask } from "@/trigger/example";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
@@ -60,7 +60,7 @@ In your new file, add the following code:
```ts /app/api/webhook-handler/route.ts
import type { helloWorldTask } from "@/trigger/example";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
diff --git a/docs/guides/frameworks/nextjs.mdx b/docs/guides/frameworks/nextjs.mdx
index 675ce91611..78a54b7c21 100644
--- a/docs/guides/frameworks/nextjs.mdx
+++ b/docs/guides/frameworks/nextjs.mdx
@@ -67,7 +67,7 @@ Here are the steps to trigger your task in the Next.js App and Pages router and
```ts app/api/hello-world/route.ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { helloWorldTask } from "@/trigger/example";
- import { tasks } from "@trigger.dev/sdk/v3";
+ import { tasks } from "@trigger.dev/sdk";
import { NextResponse } from "next/server";
//tasks.trigger also works with the edge runtime
@@ -107,7 +107,7 @@ Here are the steps to trigger your task in the Next.js App and Pages router and
"use server";
import type { helloWorldTask } from "@/trigger/example";
- import { tasks } from "@trigger.dev/sdk/v3";
+ import { tasks } from "@trigger.dev/sdk";
export async function myTask() {
try {
@@ -220,7 +220,7 @@ Here are the steps to trigger your task in the Next.js App and Pages router and
```ts pages/api/hello-world.ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { helloWorldTask } from "@/trigger/example";
- import { tasks } from "@trigger.dev/sdk/v3";
+ import { tasks } from "@trigger.dev/sdk";
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
@@ -263,7 +263,7 @@ If you want to automatically sync environment variables from your Vercel project
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncVercelEnvVars } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -370,7 +370,7 @@ To run this task in production, you will need to set the `REVALIDATION_SECRET` e
```ts trigger/revalidate-path.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
const NEXTJS_APP_URL = process.env.NEXTJS_APP_URL; // e.g. "http://localhost:3000" or "https://my-nextjs-app.vercel.app"
const REVALIDATION_SECRET = process.env.REVALIDATION_SECRET; // Create a REVALIDATION_SECRET and set it in your environment variables
diff --git a/docs/guides/frameworks/prisma.mdx b/docs/guides/frameworks/prisma.mdx
index b85c33b70c..0d9fcc8ac3 100644
--- a/docs/guides/frameworks/prisma.mdx
+++ b/docs/guides/frameworks/prisma.mdx
@@ -51,7 +51,7 @@ This is a simple task that will add a new user to the database.
```ts /trigger/prisma-add-new-user.ts
import { PrismaClient } from "@prisma/client";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
// Initialize Prisma client
const prisma = new PrismaClient();
@@ -117,7 +117,7 @@ We use OpenTelemetry to [instrument](https://trigger.dev/docs/config/config-file
If you want to automatically log all Prisma queries and mutations, you can use the Prisma instrumentation extension.
```js /trigger.config.js
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { PrismaInstrumentation } from "@prisma/instrumentation";
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
diff --git a/docs/guides/frameworks/remix-webhooks.mdx b/docs/guides/frameworks/remix-webhooks.mdx
index 2a4270a3ef..a62d90cb9d 100644
--- a/docs/guides/frameworks/remix-webhooks.mdx
+++ b/docs/guides/frameworks/remix-webhooks.mdx
@@ -28,7 +28,7 @@ In your new file, add the following code:
```ts /api/webhook-handler.ts
import type { ActionFunctionArgs } from "@remix-run/node";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import { helloWorldTask } from "src/trigger/example";
export async function action({ request }: ActionFunctionArgs) {
diff --git a/docs/guides/frameworks/remix.mdx b/docs/guides/frameworks/remix.mdx
index 7bbc70429b..d8fdb3450a 100644
--- a/docs/guides/frameworks/remix.mdx
+++ b/docs/guides/frameworks/remix.mdx
@@ -50,7 +50,7 @@ Add this code to your `api.hello-world.ts` file which imports your task:
```ts app/routes/api.hello-world.ts
import type { helloWorldTask } from "../../src/trigger/example";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
export async function loader() {
const handle = await tasks.trigger("hello-world", "James");
@@ -80,7 +80,7 @@ export async function loader() {
Before we start, it's important to note that:
- We'll be using a type-only import for the task to ensure compatibility with the edge runtime.
-- The `@trigger.dev/sdk/v3` package supports the edge runtime out of the box.
+- The `@trigger.dev/sdk` package supports the edge runtime out of the box.
There are a few extra steps to follow to deploy your `/api/hello-world` API endpoint to Vercel Edge Functions.
@@ -91,7 +91,7 @@ There are a few extra steps to follow to deploy your `/api/hello-world` API endp
Update your API route to use the `runtime: "edge"` option and change it to an `action()` so we can trigger the task from a curl request later on.
```ts app/routes/api.hello-world.ts
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { helloWorldTask } from "../../src/trigger/example";
// 👆 **type-only** import
diff --git a/docs/guides/frameworks/sequin.mdx b/docs/guides/frameworks/sequin.mdx
index 986cd6f133..39ff5523d8 100644
--- a/docs/guides/frameworks/sequin.mdx
+++ b/docs/guides/frameworks/sequin.mdx
@@ -40,7 +40,7 @@ Start by creating a new Trigger.dev task that takes in a Sequin change event as
```ts trigger/create-embedding-for-post.ts
- import { task } from "@trigger.dev/sdk/v3";
+ import { task } from "@trigger.dev/sdk";
import { OpenAI } from "openai";
import { upsertEmbedding } from "../util";
@@ -161,7 +161,7 @@ You'll now create an API endpoint that will receive posts from Sequin and then t
```ts app/api/create-embedding-for-post/route.ts
import type { createEmbeddingForPost } from "@/trigger/create-embedding-for-post";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import { NextResponse } from "next/server";
export async function POST(req: Request) {
diff --git a/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx b/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx
index 71bb59dcd7..89f31b4b53 100644
--- a/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx
+++ b/docs/guides/frameworks/supabase-edge-functions-database-webhooks.mdx
@@ -147,7 +147,7 @@ These dependencies will allow you to interact with the Deepgram and Supabase API
// Install any missing dependencies below
import { createClient as createDeepgramClient } from "@deepgram/sdk";
import { createClient as createSupabaseClient } from "@supabase/supabase-js";
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import ffmpeg from "fluent-ffmpeg";
import fs from "fs";
import { Readable } from "node:stream";
@@ -255,7 +255,7 @@ Before you can deploy the task, you'll need to add the FFmpeg build extension to
```ts trigger.config.ts
// Add this import
import { ffmpeg } from "@trigger.dev/build/extensions/core";
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "", // Replace with your project ref
diff --git a/docs/guides/new-build-system-preview.mdx b/docs/guides/new-build-system-preview.mdx
index 984092cd27..f4064c2db5 100644
--- a/docs/guides/new-build-system-preview.mdx
+++ b/docs/guides/new-build-system-preview.mdx
@@ -47,10 +47,10 @@ The new build system does not effect your trigger task files at all, so those ca
### `defineConfig`
-You should now import the `defineConfig` function from `@trigger.dev/sdk/v3` and export the config as the default export:
+You should now import the `defineConfig` function from `@trigger.dev/sdk` and export the config as the default export:
```
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -66,7 +66,7 @@ The new build system will bundle all dependencies by default, so `dependenciesTo
Now that all dependencies are bundled, there are some situations where bundling a dependency doesn't work, and needs to be made external (e.g. when a dependency includes a native module). You can now specify these dependencies as build externals in the `defineConfig` function:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -91,7 +91,7 @@ npm add @trigger.dev/build@0.0.0-prerelease-20240911144933 -D
Now you can import the `additionalFiles` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { additionalFiles } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -117,7 +117,7 @@ npm add @trigger.dev/build@0.0.0-prerelease-20240911144933 -D
Now you can import the `additionalPackages` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { additionalPackages } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -141,7 +141,7 @@ npm add @trigger.dev/build@0.0.0-prerelease-20240911144933 -D
Now you can import the `syncEnvVars` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncEnvVars } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -167,7 +167,7 @@ One other difference is now `params.env` only contains the environment variables
If you make use of decorators in your code, and have enabled the `emitDecoratorMetadata` tsconfig compiler option, you'll need to enable this in the new build sytem using the `emitDecoratorMetadata` build extension:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { emitDecoratorMetadata } from "@trigger.dev/build/extensions/typescript";
export default defineConfig({
@@ -189,7 +189,7 @@ npm add @trigger.dev/build@0.0.0-prerelease-20240911144933 -D
Then you can import the `prismaExtension` build extension and use it in your `trigger.config.ts` file, passing in the path to your Prisma schema file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -214,7 +214,7 @@ This will make sure that your prisma client is generated during the build proces
If you want to also run migrations during the build process, you can pass in the `migrate` option:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -256,7 +256,7 @@ generator kysely {
```
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -279,7 +279,7 @@ export default defineConfig({
Previously, we installed [Audio Waveform](https://github.com/bbc/audiowaveform) in the build image. That's been moved to a build extension:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { audioWaveform } from "@trigger.dev/build/extensions/audioWaveform";
export default defineConfig({
@@ -295,7 +295,7 @@ export default defineConfig({
You can now add esbuild plugins to customize the build process using the `esbuildPlugin` build extension. The example below shows how to automatically upload sourcemaps to Sentry using their esbuild plugin:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { esbuildPlugin } from "@trigger.dev/build/extensions";
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";
diff --git a/docs/guides/python/python-crawl4ai.mdx b/docs/guides/python/python-crawl4ai.mdx
index 526d0eaf58..8cb0d7f210 100644
--- a/docs/guides/python/python-crawl4ai.mdx
+++ b/docs/guides/python/python-crawl4ai.mdx
@@ -60,7 +60,7 @@ Once you have a proxy service, set the following environment variables in your T
After you've initialized your project with Trigger.dev, add these build settings to your `trigger.config.ts` file:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { pythonExtension } from "@trigger.dev/python/extension";
import type { BuildContext, BuildExtension } from "@trigger.dev/core/v3/build";
@@ -123,7 +123,7 @@ export function installPlaywrightChromium(): BuildExtension {
This task uses the `python.runScript` method to run the `crawl-url.py` script with the given URL as an argument. You can see the original task in our examples repository [here](https://github.com/triggerdotdev/examples/blob/main/python-crawl4ai/src/trigger/pythonTasks.ts).
```ts src/trigger/pythonTasks.ts
-import { logger, schemaTask, task } from "@trigger.dev/sdk/v3";
+import { logger, schemaTask, task } from "@trigger.dev/sdk";
import { python } from "@trigger.dev/python";
import { z } from "zod";
diff --git a/docs/guides/python/python-doc-to-markdown.mdx b/docs/guides/python/python-doc-to-markdown.mdx
index a36a240cec..43b2a28b4d 100644
--- a/docs/guides/python/python-doc-to-markdown.mdx
+++ b/docs/guides/python/python-doc-to-markdown.mdx
@@ -6,11 +6,6 @@ description: "Learn how to use Trigger.dev with Python to convert documents to m
import PythonLearnMore from "/snippets/python-learn-more.mdx";
-
- This project uses Trigger.dev v4 (which is currently in beta as of 28 April 2025). If you want to
- run this project you will need to [upgrade to v4](/upgrade-to-v4).
-
-
## Overview
Convert documents to markdown using Microsoft's [MarkItDown](https://github.com/microsoft/markitdown) library. This can be especially useful for preparing documents in a structured format for AI applications.
@@ -45,7 +40,7 @@ After you've initialized your project with Trigger.dev, add these build settings
```ts trigger.config.ts
import { pythonExtension } from "@trigger.dev/python/extension";
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
runtime: "node",
@@ -76,7 +71,7 @@ export default defineConfig({
This task uses the `python.runScript` method to run the `markdown-converter.py` script with the given document URL as an argument.
```ts src/trigger/convertToMarkdown.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { python } from "@trigger.dev/python";
import * as fs from "fs";
import * as path from "path";
diff --git a/docs/guides/python/python-image-processing.mdx b/docs/guides/python/python-image-processing.mdx
index 0f81d2b54f..26987dbaf2 100644
--- a/docs/guides/python/python-image-processing.mdx
+++ b/docs/guides/python/python-image-processing.mdx
@@ -42,7 +42,7 @@ After you've initialized your project with Trigger.dev, add these build settings
```ts trigger.config.ts
import { pythonExtension } from "@trigger.dev/python/extension";
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
runtime: "node",
@@ -73,7 +73,7 @@ export default defineConfig({
This task uses the `python.runScript` method to run the `image-processing.py` script with the given image URL as an argument. You can adjust the image processing parameters in the payload, with options such as height, width, quality, output format, etc.
```ts src/trigger/processImage.ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { z } from "zod";
import { python } from "@trigger.dev/python";
import { promises as fs } from "fs";
diff --git a/docs/guides/python/python-pdf-form-extractor.mdx b/docs/guides/python/python-pdf-form-extractor.mdx
index 3367ea9baf..0b8c856d79 100644
--- a/docs/guides/python/python-pdf-form-extractor.mdx
+++ b/docs/guides/python/python-pdf-form-extractor.mdx
@@ -41,7 +41,7 @@ After you've initialized your project with Trigger.dev, add these build settings
```ts trigger.config.ts
import { pythonExtension } from "@trigger.dev/python/extension";
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
runtime: "node",
@@ -72,7 +72,7 @@ export default defineConfig({
This task uses the `python.runScript` method to run the `image-processing.py` script with the given image URL as an argument. You can adjust the image processing parameters in the payload, with options such as height, width, quality, output format, etc.
```ts src/trigger/pythonPdfTask.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { python } from "@trigger.dev/python";
export const processPdfForm = task({
diff --git a/docs/guides/use-cases/upgrading-from-v2.mdx b/docs/guides/use-cases/upgrading-from-v2.mdx
index 05f73b9a3f..3cc1f88be7 100644
--- a/docs/guides/use-cases/upgrading-from-v2.mdx
+++ b/docs/guides/use-cases/upgrading-from-v2.mdx
@@ -59,7 +59,7 @@ client.defineJob({
In v3 it looks like this:
```ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import { db } from "@/lib/db";
export const getCreatorVideosFromTikTok = task({
id: "my-job-id",
@@ -136,7 +136,7 @@ export const openaiJob = task({
So don't use the `@trigger.dev/openai` package in v3, use the official OpenAI SDK.
Bear in mind that the syntax for the latest official SDK will probably be different from the @trigger.dev integration SDK. You will need to adapt the code accordingly.
3. The most critical difference is that inside the `run` function you do NOT need to wrap everything in `io.runTask`. So anything inside there can be extracted out and be used in the main body of the function without wrapping it.
-4. The import for `task` in v3 is `import { task } from "@trigger.dev/sdk/v3";`
+4. The import for `task` in v3 is `import { task } from "@trigger.dev/sdk";`
5. You can trigger jobs from other jobs. In v2 this was typically done by either calling `io.sendEvent()` or by calling `yourOtherTask.invoke()`. In v3 you call `.trigger()` on the other task, there are no events in v3.
v2:
@@ -258,7 +258,7 @@ client.defineJob({
In v3 we eliminate a lot of code mainly because we don't need tricks to try avoid timeouts. Here's the equivalent v3 code:
```ts v3 OpenAI task
-import { logger, task, wait } from "@trigger.dev/sdk/v3";
+import { logger, task, wait } from "@trigger.dev/sdk";
//1. Official OpenAI SDK
import OpenAI from "openai";
diff --git a/docs/hidden-tasks.mdx b/docs/hidden-tasks.mdx
new file mode 100644
index 0000000000..1624a11ecf
--- /dev/null
+++ b/docs/hidden-tasks.mdx
@@ -0,0 +1,56 @@
+---
+title: "Hidden tasks"
+description: "Create tasks that are not exported from your trigger files but can still be executed."
+---
+
+Hidden tasks are tasks that are not exported from your trigger files but can still be executed. These tasks are only accessible to other tasks within the same file or module where they're defined.
+
+```ts trigger/my-task.ts
+import { task } from "@trigger.dev/sdk";
+
+// This is a hidden task - not exported
+const internalTask = task({
+ id: "internal-processing",
+ run: async (payload: any, { ctx }) => {
+ // Internal processing logic
+ },
+});
+```
+
+Hidden tasks are useful for creating internal workflows that should only be triggered by other tasks in the same file:
+
+```ts trigger/my-workflow.ts
+import { task } from "@trigger.dev/sdk";
+
+// Hidden task for internal use
+const processData = task({
+ id: "process-data",
+ run: async (payload: { data: string }, { ctx }) => {
+ // Process the data
+ return { processed: payload.data.toUpperCase() };
+ },
+});
+
+// Public task that uses the hidden task
+export const mainWorkflow = task({
+ id: "main-workflow",
+ run: async (payload: any, { ctx }) => {
+ const result = await processData.trigger({ data: payload.input });
+ return result;
+ },
+});
+```
+
+You can also create packages of reusable tasks that can be imported and used without needing to re-export them:
+
+```ts trigger/my-task.ts
+import { task } from "@trigger.dev/sdk";
+import { sendToSlack } from "@repo/tasks"; // Hidden task from another package
+
+export const notificationTask = task({
+ id: "send-notification",
+ run: async (payload: any, { ctx }) => {
+ await sendToSlack.trigger(payload);
+ },
+});
+```
\ No newline at end of file
diff --git a/docs/how-it-works.mdx b/docs/how-it-works.mdx
index a1eafc53bc..3e2857f157 100644
--- a/docs/how-it-works.mdx
+++ b/docs/how-it-works.mdx
@@ -11,7 +11,7 @@ Trigger.dev v3 allows you to integrate long-running async tasks into your applic
For example, the below task processes a video with `ffmpeg` and sends the results to an s3 bucket, then updates a database with the results and sends an email to the user.
```ts /trigger/video.ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
import { updateVideoUrl } from "../db.js";
import ffmpeg from "fluent-ffmpeg";
import { Readable } from "node:stream";
@@ -85,7 +85,7 @@ Now in your application, you can trigger this task by calling:
```ts
import { NextResponse } from "next/server";
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { convertVideo } from "./trigger/video";
// 👆 **type-only** import
@@ -165,7 +165,7 @@ This approach allows Trigger.dev to manage resources efficiently, handle complex
Example of a parent and child task using the Checkpoint-Resume System:
```ts
-import { task, wait } from "@trigger.dev/sdk/v3";
+import { task, wait } from "@trigger.dev/sdk";
export const parentTask = task({
id: "parent-task",
@@ -249,7 +249,7 @@ Let's rewrite the `convert-video` task above to be more durable:
```ts /trigger/video.ts
-import { idempotencyKeys, logger, task } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, logger, task } from "@trigger.dev/sdk";
import { processVideo, sendUserEmail, uploadToS3 } from "./tasks.js";
import { updateVideoUrl } from "../db.js";
@@ -287,7 +287,7 @@ export const convertVideo = task({
```
```ts /trigger/tasks.ts
-import { task, logger } from "@trigger.dev/sdk/v3";
+import { task, logger } from "@trigger.dev/sdk";
import ffmpeg from "fluent-ffmpeg";
import { Readable } from "node:stream";
import type { ReadableStream } from "node:stream/web";
@@ -441,7 +441,7 @@ The Trigger.dev logging and task dashboard is powered by OpenTelemetry traces an
Because we use standard OpenTelemetry, you can instrument your code and OpenTelemetry compatible libraries to get detailed traces and logs of your tasks. The above trace instruments both Prisma and the AWS SDK:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { PrismaInstrumentation } from "@prisma/instrumentation";
import { AwsInstrumentation } from "@opentelemetry/instrumentation-aws-sdk";
diff --git a/docs/idempotency.mdx b/docs/idempotency.mdx
index e9400a77eb..56898c3cfd 100644
--- a/docs/idempotency.mdx
+++ b/docs/idempotency.mdx
@@ -16,7 +16,7 @@ We currently support idempotency at the task level, meaning that if you trigger
You can provide an `idempotencyKey` to ensure that a task is only triggered once with the same key. This is useful if you are triggering a task within another task that might be retried:
```ts
-import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, task } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -41,7 +41,7 @@ You can use the `idempotencyKeys.create` SDK function to create an idempotency k
We automatically inject the run ID when generating the idempotency key when running inside a task by default. You can turn it off by passing the `scope` option to `idempotencyKeys.create`:
```ts
-import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, task } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -61,7 +61,7 @@ export const myTask = task({
If you are triggering a task from your backend code, you can use the `idempotencyKeys.create` SDK function to create an idempotency key.
```ts
-import { idempotencyKeys, tasks } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, tasks } from "@trigger.dev/sdk";
// You can also pass an array of strings to create a idempotency key
const idempotencyKey = await idempotencyKeys.create([myUser.id, "my-task"]);
@@ -82,7 +82,7 @@ await myTask.trigger({ some: "data" }, { idempotencyKey: myUser.id });
You can pass the `idempotencyKey` when calling `batchTrigger` as well:
```ts
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
await tasks.batchTrigger("my-task", [
{
@@ -105,7 +105,7 @@ The `idempotencyKeyTTL` option defines a time window during which a task with th
By default idempotency keys are stored for 30 days. You can change this by passing the `idempotencyKeyTTL` option when triggering a task:
```ts
-import { idempotencyKeys, task, wait } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, task, wait } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -141,7 +141,7 @@ You can use the following units for the `idempotencyKeyTTL` option:
We don't currently support payload-based idempotency, but you can implement it yourself by hashing the payload and using the hash as the idempotency key.
```ts
-import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, task } from "@trigger.dev/sdk";
import { createHash } from "node:crypto";
// Somewhere in your code
diff --git a/docs/images/bulk-action-create.png b/docs/images/bulk-action-create.png
new file mode 100644
index 0000000000..91d11f8c30
Binary files /dev/null and b/docs/images/bulk-action-create.png differ
diff --git a/docs/images/bulk-action-open-panel.png b/docs/images/bulk-action-open-panel.png
new file mode 100644
index 0000000000..3887d1000d
Binary files /dev/null and b/docs/images/bulk-action-open-panel.png differ
diff --git a/docs/images/bulk-action-page.png b/docs/images/bulk-action-page.png
new file mode 100644
index 0000000000..c0a9cce1cc
Binary files /dev/null and b/docs/images/bulk-action-page.png differ
diff --git a/docs/images/priority-runs.png b/docs/images/priority-runs.png
new file mode 100644
index 0000000000..bad6922f05
Binary files /dev/null and b/docs/images/priority-runs.png differ
diff --git a/docs/images/test-dashboard.png b/docs/images/test-dashboard.png
new file mode 100644
index 0000000000..14fccdbddd
Binary files /dev/null and b/docs/images/test-dashboard.png differ
diff --git a/docs/images/test-page.png b/docs/images/test-page.png
deleted file mode 100644
index e700283996..0000000000
Binary files a/docs/images/test-page.png and /dev/null differ
diff --git a/docs/images/test-select-environment.png b/docs/images/test-select-environment.png
deleted file mode 100644
index 078162461c..0000000000
Binary files a/docs/images/test-select-environment.png and /dev/null differ
diff --git a/docs/images/test-select-task.png b/docs/images/test-select-task.png
deleted file mode 100644
index ec7a6fac02..0000000000
Binary files a/docs/images/test-select-task.png and /dev/null differ
diff --git a/docs/images/test-set-payload.png b/docs/images/test-set-payload.png
deleted file mode 100644
index b0c3a5661f..0000000000
Binary files a/docs/images/test-set-payload.png and /dev/null differ
diff --git a/docs/logging.mdx b/docs/logging.mdx
index 90ead35b94..dfc8b0750e 100644
--- a/docs/logging.mdx
+++ b/docs/logging.mdx
@@ -16,7 +16,7 @@ You can use `console.log()`, `console.error()`, etc as normal and they will be s
We recommend that you use our `logger` object which creates structured logs. Structured logs will make it easier for you to search the logs to quickly find runs.
```ts /trigger/logging.ts
-import { task, logger } from "@trigger.dev/sdk/v3";
+import { task, logger } from "@trigger.dev/sdk";
export const loggingExample = task({
id: "logging-example",
@@ -54,7 +54,7 @@ You can [add instrumentations](/config/config-file#instrumentations). The Prisma
If you want to add custom traces to your code, you can use the `logger.trace` function. It will create a new OTEL trace and you can set attributes on it.
```ts
-import { logger, task } from "@trigger.dev/sdk/v3";
+import { logger, task } from "@trigger.dev/sdk";
export const customTrace = task({
id: "custom-trace",
diff --git a/docs/machines.mdx b/docs/machines.mdx
index 486b4fef81..0b60926eaf 100644
--- a/docs/machines.mdx
+++ b/docs/machines.mdx
@@ -6,7 +6,7 @@ description: "Configure the number of vCPUs and GBs of RAM you want the task to
The `machine` configuration is optional. Using higher spec machines will increase the cost of running the task but can also improve the performance of the task if it is CPU or memory bound.
```ts /trigger/heavy-task.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const heavyTask = task({
id: "heavy-task",
@@ -20,7 +20,7 @@ export const heavyTask = task({
The default machine is `small-1x` which has 0.5 vCPU and 0.5 GB of RAM. You can change the default machine in your `trigger.config.ts` file:
```ts trigger.config.ts
-import type { TriggerConfig } from "@trigger.dev/sdk/v3";
+import type { TriggerConfig } from "@trigger.dev/sdk";
export const config: TriggerConfig = {
machine: "small-2x",
@@ -67,8 +67,8 @@ We automatically detect common Out Of Memory errors, including when ffmpeg throw
You can explicitly throw an Out Of Memory error in your task. This can be useful if you use a native package that detects it's going to run out of memory and then stops before it runs out. If you can detect this, you can then throw this error.
```ts /trigger/heavy-task.ts
-import { task } from "@trigger.dev/sdk/v3";
-import { OutOfMemoryError } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
+import { OutOfMemoryError } from "@trigger.dev/sdk";
export const yourTask = task({
id: "your-task",
@@ -88,7 +88,7 @@ If OOM errors happen regularly you need to either optimize the memory-efficiency
If you are seeing rare OOM errors, it might make sense to add a setting to your task to retry with a large machine when an OOM happens:
```ts /trigger/heavy-task.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const yourTask = task({
id: "your-task",
diff --git a/docs/management/advanced-usage.mdx b/docs/management/advanced-usage.mdx
index 0413d1690b..b0a0cbd2aa 100644
--- a/docs/management/advanced-usage.mdx
+++ b/docs/management/advanced-usage.mdx
@@ -9,7 +9,7 @@ description: Advanced usage of the Trigger.dev management API
All API methods return a `Promise` subclass `ApiPromise` that includes helpers for accessing the underlying HTTP response:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
async function main() {
const { data: run, response: raw } = await runs.retrieve("run_1234").withResponse();
diff --git a/docs/management/authentication.mdx b/docs/management/authentication.mdx
index 2d24c1f354..62eef951db 100644
--- a/docs/management/authentication.mdx
+++ b/docs/management/authentication.mdx
@@ -15,7 +15,7 @@ There are two methods of authenticating with the management API: using a secret
Certain API functions work with both authentication methods, but require different arguments depending on the method used. For example, the `runs.list` function can be called using either a `secretKey` or a `personalAccessToken`, but the `projectRef` argument is required when using a `personalAccessToken`:
```ts
-import { configure, runs } from "@trigger.dev/sdk/v3";
+import { configure, runs } from "@trigger.dev/sdk";
// Using secretKey authentication
configure({
@@ -82,7 +82,7 @@ A PAT is a token associated with a specific user, and gives access to all the or
For example, when uploading environment variables using a PAT, you must provide the `projectRef` and `environment` arguments:
```ts
-import { configure, envvars } from "@trigger.dev/sdk/v3";
+import { configure, envvars } from "@trigger.dev/sdk";
configure({
secretKey: process.env["TRIGGER_ACCESS_TOKEN"], // starts with tr_pat_
@@ -94,4 +94,64 @@ await envvars.upload("proj_1234", "dev", {
},
override: true,
});
+```
+
+### Preview branch targeting
+
+When working with preview branches, you may need to target a specific branch when making API calls. This is particularly useful for managing environment variables or other resources that are scoped to individual preview branches.
+
+
+
+ To target a specific preview branch, include the `previewBranch` option in your SDK configuration:
+
+```ts
+import { configure, envvars } from "@trigger.dev/sdk";
+
+configure({
+ secretKey: process.env["TRIGGER_ACCESS_TOKEN"], // starts with tr_pat_
+ previewBranch: "feature-xyz",
+});
+
+await envvars.update("proj_1234", "preview", "DATABASE_URL", {
+ value: "your_preview_database_url",
+});
+```
+
+
+
+ To target a specific preview branch, include the `x-trigger-branch` header in your API requests with the branch name as the value:
+
+```bash
+curl --request PUT \
+ --url https://api.trigger.dev/api/v1/projects/{projectRef}/envvars/preview/DATABASE_URL \
+ --header 'Authorization: Bearer ' \
+ --header 'x-trigger-branch: feature-xyz' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "value": "your_preview_database_url"
+ }'
+```
+
+
+This will set the `DATABASE_URL` environment variable specifically for the `feature-xyz` preview branch.
+
+
+ The `x-trigger-branch` header is only relevant when working with the `preview` environment (`{env}` parameter set to `preview`). It has no effect when working with `dev`, `staging`, or `prod` environments.
+
+
+#### SDK usage with preview branches
+
+When using the SDK to manage preview branch environment variables, the branch targeting is handled automatically when you're running in a preview environment with the `TRIGGER_PREVIEW_BRANCH` environment variable set. However, you can also specify the branch explicitly:
+
+```ts
+import { configure, envvars } from "@trigger.dev/sdk";
+
+configure({
+ secretKey: process.env["TRIGGER_ACCESS_TOKEN"], // starts with tr_pat_
+ previewBranch: "feature-xyz", // Optional: specify the branch
+});
+
+await envvars.update("proj_1234", "preview", "DATABASE_URL", {
+ value: "your_preview_database_url",
+});
```
\ No newline at end of file
diff --git a/docs/management/auto-pagination.mdx b/docs/management/auto-pagination.mdx
index 67fa69467b..3d5159e120 100644
--- a/docs/management/auto-pagination.mdx
+++ b/docs/management/auto-pagination.mdx
@@ -8,7 +8,7 @@ All list endpoints in the management API support auto-pagination.
You can use `for await … of` syntax to iterate through items across all pages:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
async function fetchAllRuns() {
const allRuns = [];
@@ -24,7 +24,7 @@ async function fetchAllRuns() {
You can also use helpers on the return value from any `list` method to get the next/previous page of results:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
async function main() {
let page = await runs.list({ limit: 10 });
diff --git a/docs/management/errors-and-retries.mdx b/docs/management/errors-and-retries.mdx
index cbb7ebf3d8..53a50653a5 100644
--- a/docs/management/errors-and-retries.mdx
+++ b/docs/management/errors-and-retries.mdx
@@ -9,7 +9,7 @@ description: Handling errors and retries with the Trigger.dev management API
When the SDK method is unable to connect to the API server, or the API server returns a non-successful response, the SDK will throw an `ApiError` that you can catch and handle:
```ts
-import { runs, APIError } from "@trigger.dev/sdk/v3";
+import { runs, APIError } from "@trigger.dev/sdk";
async function main() {
try {
@@ -31,7 +31,7 @@ The SDK will automatically retry requests that fail due to network errors or ser
You can customize the retry behavior by passing a `requestOptions` option to the `configure` function:
```ts
-import { configure } from "@trigger.dev/sdk/v3";
+import { configure } from "@trigger.dev/sdk";
configure({
requestOptions: {
@@ -49,7 +49,7 @@ configure({
All SDK functions also take a `requestOptions` parameter as the last argument, which can be used to customize the request options. You can use this to disable retries for a specific request:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
async function main() {
const run = await runs.retrieve("run_1234", {
diff --git a/docs/management/overview.mdx b/docs/management/overview.mdx
index 1c5467006d..0a7ca5a44a 100644
--- a/docs/management/overview.mdx
+++ b/docs/management/overview.mdx
@@ -26,10 +26,10 @@ yarn add @trigger.dev/sdk@latest
## Usage
-All `v3` functionality is provided through the `@trigger.dev/sdk/v3` module. You can import the entire module or individual resources as needed.
+All `v3` functionality is provided through the `@trigger.dev/sdk` module. You can import the entire module or individual resources as needed.
```ts
-import { configure, runs } from "@trigger.dev/sdk/v3";
+import { configure, runs } from "@trigger.dev/sdk";
configure({
// this is the default and if the `TRIGGER_SECRET_KEY` environment variable is set, can omit calling configure
diff --git a/docs/migrating-from-v3.mdx b/docs/migrating-from-v3.mdx
new file mode 100644
index 0000000000..d177e26a76
--- /dev/null
+++ b/docs/migrating-from-v3.mdx
@@ -0,0 +1,329 @@
+---
+title: "Migrating from v3"
+description: "What's new in v4, how to migrate, and breaking changes."
+---
+
+import NodeVersions from "/snippets/node-versions.mdx";
+import MigrateV4UsingAi from "/snippets/migrate-v4-using-ai.mdx";
+
+## What's new in v4?
+
+| Feature | Description |
+|:--------|:------------|
+| [Wait for token](/wait-for-token) | Create and wait for tokens to be completed, enabling approval workflows and waiting for arbitrary external conditions. |
+| Wait idempotency | Skip waits if the same idempotency key is used again when using [wait for](/wait-for#wait-idempotency), [wait until](/wait-until#wait-idempotency), or [wait for token](/wait-for-token#wait-idempotency). |
+| [Priority](/runs/priority) | Specify a priority when triggering a task. |
+| [Global lifecycle hooks](/tasks/overview#global-lifecycle-hooks) | Register global lifecycle hooks that are executed for all runs, regardless of the task. |
+| [onWait and onResume](/tasks/overview#onwait-and-onresume-functions) | Run code when a run is paused or resumed because of a wait. |
+| [onComplete](/tasks/overview#oncomplete-function) | Run code when a run completes, regardless of whether it succeeded or failed. |
+| [onCancel](/tasks/overview#oncancel-function) | Run code when a run is cancelled. |
+| [Hidden tasks](/hidden-tasks) | Create tasks that are not exported from your trigger files but can still be executed. |
+| [Middleware & locals](#middleware-and-locals) | The middleware system runs at the top level, executing before and after all lifecycle hooks. The locals API allows sharing data between middleware and hooks. |
+| [useWaitToken](/frontend/react-hooks/use-wait-token) | Use the useWaitToken hook to complete a wait token from a React component. |
+| [ai.tool](/tasks/schemaTask#ai-tool) | Create an AI tool from an existing `schemaTask` to use with the Vercel [AI SDK](https://vercel.com/docs/ai-sdk). |
+
+## Node.js support
+
+
+
+## How to migrate to v4
+
+First read the deprecations and breaking changes sections below.
+
+We recommend the following steps to migrate to v4:
+
+1. Install the v4 package.
+2. Run the `trigger dev` CLI command and test your tasks locally, fixing any breaking changes.
+3. Deploy to the staging environment and test your tasks in staging, fixing any breaking changes. (this step is optional, but highly recommended)
+4. Once you've verified that v4 is working as expected, you should deploy your application backend with the updated v4 package.
+5. Once you've deployed your application backend, you should deploy your tasks to the production environment.
+
+Note that between steps 4 and 5, runs triggered with the v4 package will continue using v3, and only new runs triggered after step 5 is complete will use v4.
+
+
+ Once v4 is activated in your environment, there will be a period of time where old runs will
+ continue to execute using v3, while new runs will use v4. Because these engines use completely
+ different underlying queues and concurrency models, it's possible you may have up to double the
+ amount of concurrently executing runs. Once the runs drain from the old run engine, the
+ concurrency will return to normal.
+
+
+## Migrate using AI
+
+Use the prompt in the accordion below to help you migrate your v3 tasks to v4. The prompt gives good results when using Claude 4 Sonnet. You’ll need a relatively large token limit.
+
+
+
+## Installation
+
+To opt-in to using v4, you will need to update your dependencies to the latest version:
+
+
+
+```bash npx
+npx trigger.dev@latest update
+```
+
+```bash yarn
+yarn dlx trigger.dev@latest update
+```
+
+```bash pnpm
+pnpm dlx trigger.dev@latest update
+```
+
+
+
+This command should update all of your `@trigger.dev/*` packages to a `4.x` version.
+
+## Deprecations
+
+We've deprecated the following APIs:
+
+### @trigger.dev/sdk/v3
+
+We've deprecated the `@trigger.dev/sdk/v3` import path and moved to a new path:
+
+```ts
+// This still works, but will be removed in a future version
+import { task } from "@trigger.dev/sdk/v3";
+
+// This is the new path
+import { task } from "@trigger.dev/sdk";
+```
+
+### `handleError` and `init`
+
+We've renamed the `handleError` hook to `catchError` to better reflect that it can catch and react to errors. `handleError` will be removed in a future version.
+
+`init` was previously used to initialize data used in the run function:
+
+```ts
+import { task } from "@trigger.dev/sdk";
+
+const myTask = task({
+ init: async () => {
+ return {
+ myClient: new MyClient(),
+ };
+ },
+ run: async (payload: any, { ctx, init }) => {
+ const client = init.myClient;
+ await client.doSomething();
+ },
+});
+```
+
+This has now been deprecated in favor of the `locals` API and middleware. See the [Improved middleware and locals](/tasks/overview#middleware-and-locals-functions) section for more details.
+
+### toolTask
+
+We've deprecated the `toolTask` function, which created both a Trigger.dev task and a tool compatible with the Vercel [AI SDK](https://vercel.com/docs/ai-sdk):
+
+```ts
+import { toolTask, schemaTask } from "@trigger.dev/sdk";
+import { z } from "zod";
+import { generateText } from "ai";
+
+const myToolTask = toolTask({
+ id: "my-tool-task",
+ run: async (payload: any, { ctx }) => {},
+});
+
+export const myAiTask = schemaTask({
+ id: "my-ai-task",
+ schema: z.object({
+ text: z.string(),
+ }),
+ run: async (payload, { ctx }) => {
+ const { text } = await generateText({
+ prompt: payload.text,
+ model: openai("gpt-4o"),
+ tools: {
+ myToolTask,
+ },
+ });
+ },
+});
+```
+
+We've replaced the `toolTask` function with the `ai.tool` function, which creates an AI tool from an existing `schemaTask`. See the [ai.tool](/tasks/schemaTask#ai-tool) page for more details.
+
+## Breaking changes
+
+### Queue changes
+
+Previously, it was possible to specify a queue name of a queue that did not exist, along with a concurrency limit. The queue would then be created "on-demand" with the specified concurrency limit. If the queue did exist, the concurrency limit of the queue would be updated to the specified value:
+
+```ts
+await myTask.trigger({ foo: "bar" }, { queue: { name: "my-queue", concurrencyLimit: 10 } });
+```
+
+This is no longer possible, and queues must now be defined ahead of time using the `queue` function:
+
+```ts
+import { queue } from "@trigger.dev/sdk";
+
+const myQueue = queue({
+ name: "my-queue",
+ concurrencyLimit: 10,
+});
+```
+
+Now when you trigger a task, you can only specify the queue by name:
+
+```ts
+await myTask.trigger({ foo: "bar" }, { queue: "my-queue" });
+```
+
+Or you can set the queue on the task:
+
+```ts
+import { queue, task } from "@trigger.dev/sdk";
+
+const myQueue = queue({
+ name: "my-queue",
+ concurrencyLimit: 10,
+});
+
+export const myTask = task({
+ id: "my-task",
+ queue: myQueue,
+ run: async (payload: any, { ctx }) => {},
+});
+
+// You can optionally specify the queue directly on the task
+export const myTask2 = task({
+ id: "my-task-2",
+ queue: {
+ name: "my-queue-2",
+ concurrencyLimit: 50,
+ },
+ run: async (payload: any, { ctx }) => {},
+});
+```
+
+Now you can trigger these tasks without having to specify the queue name in the trigger options:
+
+```ts
+await myTask.trigger({ foo: "bar" }); // Will use the queue defined on the task
+await myTask2.trigger({ foo: "bar" }); // Will use the queue defined on the task
+```
+
+### Releasing concurrency on waits
+
+We've changed the default behavior on how concurrency is released when a run is paused or resumed because of a wait. Previously, the concurrency would be released immediately when the run was first paused, no matter the settings on the queue.
+
+Now we will no longer release concurrency on a queue that has a specified `concurrencyLimit` when a run is paused. You can go back to the previous behavior by setting the `releaseConcurrencyOnWaitpoint` option to `true` on the queue:
+
+```ts
+const myQueue = queue({
+ name: "my-queue",
+ concurrencyLimit: 10,
+ releaseConcurrencyOnWaitpoint: true,
+});
+```
+
+You can also now control whether concurrency is released when performing a wait:
+
+```ts
+// This will prevent the run from being released back into the queue when the wait starts
+await wait.for({ seconds: 10, releaseConcurrency: false });
+```
+
+The new default behavior allows you to ensure that you can control the number of executing & waiting runs on a queue, and guarantee runs will resume once they are meant to be resumed.
+
+
+ If you do choose to release concurrency on waits, be aware that it's possible a resume is delayed
+ if the concurrency that was released is not available at the time the wait completes. In this
+ case, the run will go back into the queue and will resume once concurrency becomes available.
+
+
+This new behavior effects all the wait functions:
+
+- Wait for duration (e.g. `wait.for({ seconds: 10 })`)
+- Wait for a child task to complete (e.g. `myTask.triggerAndWait()`, `myTask.batchTriggerAndWait([...])`)
+- Wait for a token to complete (e.g. `wait.forToken(tokenId)`)
+
+### Lifecycle hooks
+
+We've changed the function signatures of the lifecycle hooks to be more consistent and easier to use, by unifying all the parameters into a single object that can be destructured.
+
+Previously, hooks received a payload as the first argument and then an additional object as the second argument:
+
+```ts
+import { task } from "@trigger.dev/sdk";
+
+export const myTask = task({
+ id: "my-task",
+ onStart: (payload, { ctx }) => {},
+ run: async (payload, { ctx }) => {},
+});
+```
+
+Now, all the parameters are passed in a single object:
+
+```ts
+import { task } from "@trigger.dev/sdk";
+
+export const myTask = task({
+ id: "my-task",
+ onStart: ({ payload, ctx }) => {},
+ // The run function still uses separate parameters
+ run: async (payload, { ctx }) => {},
+});
+```
+
+This is true for all the lifecycle hooks:
+
+```ts
+import { task } from "@trigger.dev/sdk";
+
+export const myTask = task({
+ id: "my-task",
+ onStart: ({ payload, ctx, task }) => {},
+ onSuccess: ({ payload, ctx, task, output }) => {},
+ onFailure: ({ payload, ctx, task, error }) => {},
+ onWait: ({ payload, ctx, task, wait }) => {},
+ onResume: ({ payload, ctx, task, wait }) => {},
+ onComplete: ({ payload, ctx, task, result }) => {},
+ catchError: ({ payload, ctx, task, error, retry, retryAt, retryDelayInMs }) => {},
+ run: async (payload, { ctx }) => {},
+});
+```
+
+### Context changes
+
+We've made a few small changes to the `ctx` object:
+
+- `ctx.attempt.id` and `ctx.attempt.status` have been removed. `ctx.attempt.number` is still available.
+- `ctx.task.exportName` has been removed (since we no longer require tasks to be exported to be triggered).
+
+### BatchTrigger changes
+
+The `batchTrigger` function no longer returns a `runs` list directly. In v3, you could access the runs directly from the batch handle:
+
+```ts
+// In v3
+const batchHandle = await tasks.batchTrigger([
+ [myTask, { foo: "bar" }],
+ [myOtherTask, { baz: "qux" }],
+]);
+
+// You could access runs directly
+console.log(batchHandle.runs);
+```
+
+In v4, you now need to use the `runs.list()` method to get the list of runs:
+
+```ts
+// In v4
+const batchHandle = await tasks.batchTrigger([
+ [myTask, { foo: "bar" }],
+ [myOtherTask, { baz: "qux" }],
+]);
+
+// Now you need to call runs.list()
+const runs = await batchHandle.runs.list();
+console.log(runs);
+```
diff --git a/docs/migration-defer.mdx b/docs/migration-defer.mdx
index b40a29624f..0a7d7f9292 100644
--- a/docs/migration-defer.mdx
+++ b/docs/migration-defer.mdx
@@ -204,7 +204,7 @@ In Trigger.dev it looks like this:
```ts /trigger/someTasks.ts
import { performLongRunningTask } from "@/utils/performLongRunningTask";
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
//named export
export const longRunningTask = task({
@@ -259,7 +259,7 @@ export default defer.cron(sendMondayNewletter, "0 0 * * 1");
In Trigger.dev the task looks like this:
```ts
-import { schedules } from "@trigger.dev/sdk/v3";
+import { schedules } from "@trigger.dev/sdk";
//this task will run when any of the attached schedules trigger
export const sendMondayNewletter = schedules.task({
diff --git a/docs/migration-mergent.mdx b/docs/migration-mergent.mdx
index b41e691b2a..7b90675b19 100644
--- a/docs/migration-mergent.mdx
+++ b/docs/migration-mergent.mdx
@@ -48,7 +48,7 @@ This is typically called by Mergent via HTTP POST, and you’d register the endp
#### The same task in Trigger.dev
```ts trigger/processVideo.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const processVideoTask = task({
id: "process-video",
@@ -83,7 +83,7 @@ export async function dailyReportTask(req) {
**Trigger.dev scheduled task:**
```ts trigger/dailyReport.ts
-import { schedules } from "@trigger.dev/sdk/v3";
+import { schedules } from "@trigger.dev/sdk";
export const dailyReportTask = schedules.task({
id: "daily-report",
diff --git a/docs/open-source-self-hosting.mdx b/docs/open-source-self-hosting.mdx
index a3c56274ec..bbdbc910fa 100644
--- a/docs/open-source-self-hosting.mdx
+++ b/docs/open-source-self-hosting.mdx
@@ -1,14 +1,12 @@
---
title: "Docker (legacy)"
-description: "You can self-host Trigger.dev on your own infrastructure using Docker."
+description: "Self-host Trigger.dev on your own infrastructure using Docker."
---
-This guide is for v3, you can find the v4 guide [here](/self-hosting/docker).
+This is a legacy guide for self-hosting v3 using Docker, you can find the v4 guide [here](/self-hosting/docker).Security, scaling, and reliability concerns are not fully addressed here. This guide is meant for evaluation purposes and won't result in a production-ready deployment.
-This guide is for Docker only. We don't currently provide documentation for Kubernetes.
-
## Overview
diff --git a/docs/queue-concurrency.mdx b/docs/queue-concurrency.mdx
index b76e374695..cb85e2c829 100644
--- a/docs/queue-concurrency.mdx
+++ b/docs/queue-concurrency.mdx
@@ -14,9 +14,10 @@ It's important to note that only actively executing runs count towards concurren
By default, all tasks have an unbounded concurrency limit, limited only by the overall concurrency limits of your environment. This means that each task could possibly "fill up" the entire
concurrency limit of your environment.
+Each individual queue has a maximum concurrency limit equal to your environment's base concurrency limit. If you don't explicitly set a queue's concurrency limit, it will default to your environment's base concurrency limit.
+
- Your environment has a maximum concurrency limit which depends on your plan. If you're a paying
- customer you can request a higher limit by [contacting us](https://www.trigger.dev/contact).
+ Your environment has a base concurrency limit and a burstable limit (default burst factor of 2.0x the base limit). Individual queues are limited by the base concurrency limit, not the burstable limit. For example, if your base limit is 10, your environment can burst up to 20 concurrent runs, but any single queue can have at most 10 concurrent runs. If you're a paying customer you can request higher limits by [contacting us](https://www.trigger.dev/contact).
## Setting task concurrency
@@ -182,12 +183,21 @@ export const subtask = task({
## Waits and concurrency
-With our [task checkpoint system](/how-it-works#the-checkpoint-resume-system), a parent task can trigger and wait for a subtask to complete. The way this system interacts with the concurrency system is a little complicated but important to understand. There are two main scenarios that we handle slightly differently:
+With our [task checkpoint system](/how-it-works#the-checkpoint-resume-system), tasks can wait at various waitpoints (like waiting for subtasks to complete, delays, or external events). The way this system interacts with the concurrency system is important to understand.
+
+Concurrency is only released when a run reaches a waitpoint and is checkpointed. When a run is checkpointed, it transitions to the `WAITING` state and releases its concurrency slot back to both the queue and the environment, allowing other runs to execute or resume.
-- When a parent task waits for a subtask on a different queue.
-- When a parent task waits for a subtask on the same queue.
+This means that:
+- Only actively executing runs count towards concurrency limits
+- Runs in the `WAITING` state (checkpointed at waitpoints) do not consume concurrency slots
+- You can have more runs in the `WAITING` state than your queue's concurrency limit
+- When a waiting run resumes (e.g., when a subtask completes), it must re-acquire a concurrency slot
-These scenarios are discussed in more detail below:
+For example, if you have a queue with a `concurrencyLimit` of 1:
+- You can only have exactly 1 run executing at a time
+- You may have multiple runs in the `WAITING` state that belong to that queue
+- When the executing run reaches a waitpoint and checkpoints, it releases its slot
+- The next queued run can then begin execution
We sometimes refer to the parent task as the "parent" and the subtask as the "child". Subtask and
@@ -196,7 +206,7 @@ These scenarios are discussed in more detail below:
### Waiting for a subtask on a different queue
-During the time when a parent task is waiting on a subtask, the "concurrency" slot of the parent task is still considered occupied on the parent task queue, but is temporarily "released" to the environment. An example will help illustrate this:
+When a parent task triggers and waits for a subtask on a different queue, the parent task will checkpoint and release its concurrency slot once it reaches the wait point. This prevents environment deadlocks where all concurrency slots would be occupied by waiting tasks.
```ts /trigger/waiting.ts
export const parentTask = task({
@@ -205,8 +215,10 @@ export const parentTask = task({
concurrencyLimit: 1,
},
run: async (payload) => {
- //trigger a subtask
+ //trigger a subtask and wait for it to complete
await subtask.triggerAndWait(payload);
+ // The parent task checkpoints here and releases its concurrency slot
+ // allowing other tasks to execute while waiting
},
});
@@ -218,17 +230,11 @@ export const subtask = task({
});
```
-For example purposes, let's say the environment concurrency limit is 1. When the parent task is triggered, it will occupy the only slot in the environment. When the parent task triggers the subtask, the subtask will be placed in the queue for the subtask. The parent task will then wait for the subtask to complete. During this time, the parent task slot is temporarily released to the environment, allowing another task to run. Once the subtask completes, the parent task slot is reoccupied.
-
-This system prevents "stuck" tasks. If the parent task were to wait on the subtask and not release the slot, the environment would be stuck with only one task running.
-
-And because only the environment slot is released, the parent task queue slot is still occupied. This means that if another task is triggered on the parent task queue, it will be placed in the queue and wait for the parent task to complete, respecting the concurrency limit.
+When the parent task reaches the `triggerAndWait` call, it checkpoints and transitions to the `WAITING` state, releasing its concurrency slot back to both its queue and the environment. Once the subtask completes, the parent task will resume and re-acquire a concurrency slot.
### Waiting for a subtask on the same queue
-Because tasks can trigger and wait recursively, or share the same queue, we've added special handling for when a parent task waits for a subtask on the same queue.
-
-Recall above that when waiting for a subtask on a different queue, the parent task slot is temporarily released to the environment. When the parent task and the subtask share a queue, we also release the parent task slot to the queue. Again, an example will help illustrate this:
+When a parent task and subtask share the same queue, the checkpointing behavior ensures that recursive task execution can proceed without deadlocks, up to the queue's concurrency limit.
```ts /trigger/waiting-same-queue.ts
export const myQueue = queue({
@@ -240,7 +246,7 @@ export const parentTask = task({
id: "parent-task",
queue: myQueue,
run: async (payload) => {
- //trigger a subtask
+ //trigger a subtask and wait for it to complete
await subtask.triggerAndWait(payload);
},
});
@@ -254,9 +260,9 @@ export const subtask = task({
});
```
-In this example, the parent task and the subtask share the same queue with a concurrency limit of 1. When the parent task triggers the subtask, the parent task slot is released to the queue, giving the subtask the opportunity to run. Once the subtask completes, the parent task slot is reoccupied.
+When the parent task checkpoints at the `triggerAndWait` call, it releases its concurrency slot back to the queue, allowing the subtask to execute. Once the subtask completes, the parent task will resume.
-It's very important to note that we only release at-most X slots to the queue, where X is the concurrency limit of the queue. This means that you can only trigger and wait for X subtasks on the same queue. If you try to trigger and wait for more than X subtasks, you will receive a `RECURSIVE_WAIT_DEADLOCK` error. The following example will result in a deadlock:
+However, you can only have recursive waits up to your queue's concurrency limit. If you exceed this limit, you will receive a `RECURSIVE_WAIT_DEADLOCK` error:
```ts /trigger/deadlock.ts
export const myQueue = queue({
@@ -268,7 +274,6 @@ export const parentTask = task({
id: "parent-task",
queue: myQueue,
run: async (payload) => {
- //trigger a subtask
await subtask.triggerAndWait(payload);
},
});
@@ -277,8 +282,7 @@ export const subtask = task({
id: "subtask",
queue: myQueue,
run: async (payload) => {
- //trigger a subtask
- await subsubtask.triggerAndWait(payload);
+ await subsubtask.triggerAndWait(payload); // This will cause a deadlock
},
});
@@ -291,12 +295,16 @@ export const subsubtask = task({
});
```
-Now this will result in a `RECURSIVE_WAIT_DEADLOCK` error because the parent task is waiting for the subtask, and the subtask is waiting for the subsubtask, but there is no more concurrency available in the queue. It will look a bit like this in the logs:
+This results in a `RECURSIVE_WAIT_DEADLOCK` error because the queue can only support one level of recursive waiting with a concurrency limit of 1:

### Mitigating recursive wait deadlocks
-If you are recursively triggering and waiting for tasks on the same queue, you can mitigate the risk of a deadlock by increasing the concurrency limit of the queue. This will allow you to trigger and wait for more subtasks.
+To avoid recursive wait deadlocks when using shared queues:
+
+1. **Increase the queue's concurrency limit** to allow more levels of recursive waiting
+2. **Use different queues** for parent and child tasks to eliminate the possibility of deadlock
+3. **Design task hierarchies** to minimize deep recursive waiting patterns
-You can also use different queues for the parent task and the subtask. This will allow you to trigger and wait for more subtasks without the risk of a deadlock.
+Remember that the number of recursive waits you can have on a shared queue is limited by that queue's concurrency limit.
diff --git a/docs/realtime/overview.mdx b/docs/realtime/overview.mdx
index 718181dc16..126e0dfa48 100644
--- a/docs/realtime/overview.mdx
+++ b/docs/realtime/overview.mdx
@@ -5,6 +5,7 @@ description: Using the Trigger.dev v3 realtime API
---
import RealtimeExamplesCards from "/snippets/realtime-examples-cards.mdx";
+import RunBooleanHelpers from "/snippets/run-boolean-helpers.mdx";
Trigger.dev Realtime is a set of APIs that allow you to subscribe to runs and get real-time updates on the run status. This is useful for monitoring runs, updating UIs, and building realtime dashboards.
@@ -29,7 +30,7 @@ The Realtime API is built on top of [Electric SQL](https://electric-sql.com/), a
After you trigger a task, you can subscribe to the run using the `runs.subscribeToRun` function. This function returns an async iterator that you can use to get updates on the run status.
```ts
-import { runs, tasks } from "@trigger.dev/sdk/v3";
+import { runs, tasks } from "@trigger.dev/sdk";
// Somewhere in your backend code
async function myBackend() {
@@ -47,7 +48,7 @@ Every time the run changes, the async iterator will yield the updated run. You c
Alternatively, you can subscribe to changes to any run that includes a specific tag (or tags) using the `runs.subscribeToRunsWithTag` function.
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
// Somewhere in your backend code
for await (const run of runs.subscribeToRunsWithTag("user:1234")) {
@@ -59,7 +60,7 @@ for await (const run of runs.subscribeToRunsWithTag("user:1234")) {
If you've used `batchTrigger` to trigger multiple runs, you can also subscribe to changes to all the runs triggered in the batch using the `runs.subscribeToBatch` function.
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
// Somewhere in your backend code
for await (const run of runs.subscribeToBatch("batch-id")) {
@@ -195,12 +196,29 @@ The run object returned by the async iterator has the following fields:
Indicates whether this is a test run.
+## Boolean helpers
+
+Run objects returned from Realtime subscriptions include convenient boolean helper methods to check the run's status:
+
+```ts
+import { runs } from "@trigger.dev/sdk";
+
+for await (const run of runs.subscribeToRun("run_1234")) {
+ if (run.isCompleted) {
+ console.log("Run completed successfully!");
+ break;
+ }
+}
+```
+
+
+
## Type-safety
You can infer the types of the run's payload and output by passing the type of the task to the `subscribeToRun` function. This will give you type-safe access to the run's payload and output.
```ts
-import { runs, tasks } from "@trigger.dev/sdk/v3";
+import { runs, tasks } from "@trigger.dev/sdk";
import type { myTask } from "./trigger/my-task";
// Somewhere in your backend code
@@ -222,7 +240,7 @@ async function myBackend() {
When using `subscribeToRunsWithTag`, you can pass a union of task types for all the possible tasks that can have the tag.
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
import type { myTask, myOtherTask } from "./trigger/my-task";
// Somewhere in your backend code
diff --git a/docs/realtime/streams.mdx b/docs/realtime/streams.mdx
index aa74a68e09..471bb52704 100644
--- a/docs/realtime/streams.mdx
+++ b/docs/realtime/streams.mdx
@@ -17,7 +17,7 @@ The Streams API is a simple API that allows you to send data from your tasks to
To use the Streams API, you need to register a stream with a specific key using `metadata.stream`. The following example uses the OpenAI SDK with `stream: true` to stream the output of the LLM model in realtime:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
import OpenAI from "openai";
const openai = new OpenAI({
@@ -64,7 +64,7 @@ You can then subscribe to the stream using the `runs.subscribeToRun` method:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
import type { myTask, STREAMS } from "./trigger/my-task";
// Somewhere in your backend
@@ -89,7 +89,7 @@ async function subscribeToStream(runId: string) {
You can register and subscribe to multiple streams in the same task. Let's add a stream from the response body of a fetch request:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
import OpenAI from "openai";
const openai = new OpenAI({
@@ -136,7 +136,7 @@ export const myTask = task({
And then subscribing to the streams:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
import type { myTask, STREAMS } from "./trigger/my-task";
// Somewhere in your backend
@@ -205,7 +205,7 @@ The [ai SDK](https://sdk.vercel.ai/docs/introduction) provides a higher-level AP
```ts
import { openai } from "@ai-sdk/openai";
-import { logger, metadata, runs, schemaTask } from "@trigger.dev/sdk/v3";
+import { logger, metadata, runs, schemaTask } from "@trigger.dev/sdk";
import { streamText } from "ai";
import { z } from "zod";
@@ -276,7 +276,7 @@ When calling `streamText`, you can provide a `tools` object that allows the LLM
```ts
import { openai } from "@ai-sdk/openai";
-import { logger, metadata, runs, schemaTask } from "@trigger.dev/sdk/v3";
+import { logger, metadata, runs, schemaTask } from "@trigger.dev/sdk";
import { streamText, tool, type TextStreamPart } from "ai";
import { z } from "zod";
@@ -379,21 +379,22 @@ function MyComponent({ runId, publicAccessToken }: { runId: string; publicAccess
}
```
-### Using `toolTask`
+### Using `ai.tool`
-As you can see above, we defined a tool which will be used in the `aiStreamingWithTools` task. You can also define a Trigger.dev task that can be used as a tool, and will automatically be invoked with `triggerAndWait` when the tool is called. This is done using the `toolTask` function:
+As you can see above, we defined a tool which will be used in the `aiStreamingWithTools` task. You can also define a Trigger.dev task that can be used as a tool, and will automatically be invoked with `triggerAndWait` when the tool is called. This is done using the `ai.tool` function:
```ts
import { openai } from "@ai-sdk/openai";
-import { logger, metadata, runs, schemaTask, toolTask } from "@trigger.dev/sdk/v3";
+import { ai } from "@trigger.dev/sdk/ai";
+import { logger, metadata, runs, schemaTask } from "@trigger.dev/sdk";
import { streamText, tool, type TextStreamPart } from "ai";
import { z } from "zod";
-export const getWeather = toolTask({
+export const getWeatherTask = schemaTask({
id: "get-weather",
description: "Get the weather for a location",
- // Define the parameters for the tool, which becomes the task payload
- parameters: z.object({
+ // Define the schema for the task payload
+ schema: z.object({
location: z.string(),
}),
run: async ({ location }) => {
@@ -405,9 +406,11 @@ export const getWeather = toolTask({
},
});
+export const getWeatherTool = ai.tool(getWeatherTask);
+
export type STREAMS = {
// Give the stream a type of TextStreamPart along with the tools
- openai: TextStreamPart<{ getWeather: typeof getWeather.tool }>;
+ openai: TextStreamPart<{ getWeather: typeof getWeatherTool }>;
};
export const aiStreamingWithTools = schemaTask({
@@ -428,7 +431,7 @@ export const aiStreamingWithTools = schemaTask({
model: openai(model),
prompt,
tools: {
- getWeather: getWeather.tool, // pass weatherTask.tool as a tool
+ getWeather: getWeatherTool, // pass getWeatherTool as a tool
},
maxSteps: 5, // Allow streamText to repeatedly call the model
});
diff --git a/docs/realtime/subscribe-to-batch.mdx b/docs/realtime/subscribe-to-batch.mdx
index 9e0364b019..dd803872ff 100644
--- a/docs/realtime/subscribe-to-batch.mdx
+++ b/docs/realtime/subscribe-to-batch.mdx
@@ -9,7 +9,7 @@ import RunObject from "/snippets/realtime/run-object.mdx";
```ts Example
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
for await (const run of runs.subscribeToBatch("batch_1234")) {
console.log(run);
@@ -30,7 +30,7 @@ This function supports both server-side and client-side authentication. For serv
To generate a public access token, use the `auth.createPublicToken` function:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
// Somewhere in your backend code
const publicToken = await auth.createPublicToken({
diff --git a/docs/realtime/subscribe-to-run.mdx b/docs/realtime/subscribe-to-run.mdx
index c2b4d88ea7..0316a27a5b 100644
--- a/docs/realtime/subscribe-to-run.mdx
+++ b/docs/realtime/subscribe-to-run.mdx
@@ -9,7 +9,7 @@ import RunObject from "/snippets/realtime/run-object.mdx";
```ts Example
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
for await (const run of runs.subscribeToRun("run_1234")) {
console.log(run);
@@ -30,7 +30,7 @@ This function supports both server-side and client-side authentication. For serv
To generate a public access token, use the `auth.createPublicToken` function:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
// Somewhere in your backend code
const publicToken = await auth.createPublicToken({
diff --git a/docs/realtime/subscribe-to-runs-with-tag.mdx b/docs/realtime/subscribe-to-runs-with-tag.mdx
index 950a4eefaf..17405896b7 100644
--- a/docs/realtime/subscribe-to-runs-with-tag.mdx
+++ b/docs/realtime/subscribe-to-runs-with-tag.mdx
@@ -9,7 +9,7 @@ import RunObject from "/snippets/realtime/run-object.mdx";
```ts Example
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
for await (const run of runs.subscribeToRunsWithTag("user:1234")) {
console.log(run);
@@ -30,7 +30,7 @@ This function supports both server-side and client-side authentication. For serv
To generate a public access token, use the `auth.createPublicToken` function:
```ts
-import { auth } from "@trigger.dev/sdk/v3";
+import { auth } from "@trigger.dev/sdk";
// Somewhere in your backend code
const publicToken = await auth.createPublicToken({
diff --git a/docs/run-tests.mdx b/docs/run-tests.mdx
index b6cf7c2379..6598f7dbab 100644
--- a/docs/run-tests.mdx
+++ b/docs/run-tests.mdx
@@ -3,24 +3,18 @@ title: "Run tests"
description: "You can use the dashboard to run a test of your tasks."
---
-From the "Test" page in the sidebar of the dashboard you can run a test for any of your tasks, that includes for any environment.
+From the "Test" page in the side menu of the dashboard you can run a test for any of your tasks from any environment.
-
+
-
- 
-
+ Select a task to test
-
- 
-
+ Include a payload or metadata
-
- Select a recent payload as a starting point or enter from scratch. Payloads must be valid JSON – you will see helpful errors if it is not. Press the "Run test" button or use the keyboard shortcut to run the test.
-
+ Configure any additional options like the machine size, queue or delay
-
+ Select from previous test runs
-
+ Save the current test configuration as a template for later
-
+ Run the test
diff --git a/docs/run-usage.mdx b/docs/run-usage.mdx
index 2012481647..0b9163db1b 100644
--- a/docs/run-usage.mdx
+++ b/docs/run-usage.mdx
@@ -63,7 +63,7 @@ export const heavyTask = task({
You can use [runs.retrieve()](/management/runs/retrieve) to get a single run or [runs.list()](/management/runs/list) to get a list of runs. The response will include `costInCents` `baseCostInCents` and `durationMs` fields.
```ts single run
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
const run = await runs.retrieve("run-id");
console.log(run.costInCents, run.baseCostInCents, run.durationMs);
@@ -71,7 +71,7 @@ const totalCost = run.costInCents + run.baseCostInCents;
```
```ts multiple runs
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
let totalCost = 0;
for await (const run of runs.list({ tag: "user_123456" })) {
diff --git a/docs/runs.mdx b/docs/runs.mdx
index 4bba924d56..12f1cd50a9 100644
--- a/docs/runs.mdx
+++ b/docs/runs.mdx
@@ -3,6 +3,8 @@ title: "Runs"
description: "Understanding the lifecycle of task run execution in Trigger.dev"
---
+import RunBooleanHelpers from "/snippets/run-boolean-helpers.mdx";
+
In Trigger.dev, the concepts of runs and attempts are fundamental to understanding how tasks are executed and managed. This article explains these concepts in detail and provides insights into the various states a run can go through during its lifecycle.
## What are runs?
@@ -22,11 +24,10 @@ A run can go through **various** states during its lifecycle. The following diag
Runs can also find themselves in lots of other states depending on what's happening at any given time. The following sections describe all the possible states in more detail.
-### Initial States
+### Initial states
- **Waiting for deploy**:
-If a task is triggered before it has been deployed, the run enters this state and waits for the task
-to be deployed.
+ **Pending version**:
+The task is waiting for a version update because it cannot execute without additional information (task, queue, etc.).
**Delayed**: When a run is triggered
with a delay, it enters this state until the specified delay period has passed.
@@ -34,18 +35,17 @@ with a delay, it enters this state until the specified delay period has passed.
**Queued**: The run is ready
to be executed and is waiting in the queue.
-### Execution States
+ **Dequeued**: The task has been dequeued and is being sent to a worker to start executing.
- **Executing**: The task is
-currently running.
+### Execution states
- **Reattempting**: The task has
-failed and is being retried.
+ **Executing**: The task is
+currently being executed by a worker.
**Waiting**: You have used a
[triggerAndWait()](/triggering#yourtask-triggerandwait), [batchTriggerAndWait()](/triggering#yourtask-batchtriggerandwait) or a [wait function](/wait). When the wait is complete, the task will resume execution.
-### Final States
+### Final states
**Completed**: The task has successfully
finished execution.
@@ -54,21 +54,18 @@ finished execution.
by the user.
**Failed**: The task has failed
-to complete successfully.
+to complete successfully due to an error in the task code.
**Timed out**: Task has
failed because it exceeded its `maxDuration`.
**Crashed**: The worker process crashed
-during execution (likely due to an Out of Memory error).
-
- **Interrupted**: In development
-mode, when the CLI is disconnected.
+during execution (likely due to an Out of Memory error) and won’t be retried.
**System failure**: An unrecoverable system
error has occurred.
- **Expired**: The run's Time-to-Live
+ **Expired**: The run's [Time-to-Live](#time-to-live-ttl)
(TTL) has passed before it could start executing.
## Attempts
@@ -92,6 +89,35 @@ A run is considered finished when:
At this point, the run will have either an output (if successful) or an error (if failed).
+## Boolean helpers
+
+Run objects returned from the API and Realtime include convenient boolean helper methods to check the run's status:
+
+```ts
+import { runs } from "@trigger.dev/sdk";
+
+const run = await runs.retrieve("run_1234");
+
+if (run.isCompleted) {
+ console.log("Run completed successfully");
+}
+```
+
+
+
+These helpers are also available when subscribing to Realtime run updates:
+
+```ts
+import { runs } from "@trigger.dev/sdk";
+
+for await (const run of runs.subscribeToRun("run_1234")) {
+ if (run.isCompleted) {
+ console.log("Run completed successfully!");
+ break;
+ }
+}
+```
+
## Advanced run features
### Idempotency Keys
@@ -184,7 +210,7 @@ Similar to `triggerAndWait()`, the `batchTriggerAndWait()` function lets you bat
List runs in a specific environment. You can filter the runs by status, created at, task identifier, version, and more:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
// Get the first page of runs, returning up to 20 runs
let page = await runs.list({ limit: 20 });
@@ -203,7 +229,7 @@ while (page.hasNextPage()) {
You can also use an Async Iterator to get all runs:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
for await (const run of runs.list({ limit: 20 })) {
console.log(run);
@@ -213,7 +239,7 @@ for await (const run of runs.list({ limit: 20 })) {
You can provide multiple filters to the `list()` function to narrow down the results:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
const response = await runs.list({
status: ["QUEUED", "EXECUTING"], // Filter by status
@@ -232,7 +258,7 @@ const response = await runs.list({
Fetch a single run by it's ID:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
const run = await runs.retrieve(runId);
```
@@ -240,7 +266,7 @@ const run = await runs.retrieve(runId);
You can provide the type of the task to correctly type the `run.payload` and `run.output`:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
import type { myTask } from "./trigger/myTask";
const run = await runs.retrieve(runId);
@@ -252,7 +278,7 @@ console.log(run.output.bar); // string
If you have just triggered a run, you can pass the entire response object to `retrieve()` and the response will already be typed:
```ts
-import { runs, tasks } from "@trigger.dev/sdk/v3";
+import { runs, tasks } from "@trigger.dev/sdk";
import type { myTask } from "./trigger/myTask";
const response = await tasks.trigger({ foo: "bar" });
@@ -267,7 +293,7 @@ console.log(run.output.bar); // string
Cancel a run:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
await runs.cancel(runId);
```
@@ -277,7 +303,7 @@ await runs.cancel(runId);
Replay a run:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
await runs.replay(runId);
```
@@ -287,7 +313,7 @@ await runs.replay(runId);
Updates a delayed run with a new delay. Only valid when the run is in the DELAYED state.
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
await runs.reschedule(runId, { delay: "1h" });
```
@@ -297,7 +323,7 @@ await runs.reschedule(runId, { delay: "1h" });
Subscribe to changes to a specific run in real-time:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
for await (const run of runs.subscribeToRun(runId)) {
console.log(run);
@@ -307,7 +333,7 @@ for await (const run of runs.subscribeToRun(runId)) {
Similar to `runs.retrieve()`, you can provide the type of the task to correctly type the `run.payload` and `run.output`:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
import type { myTask } from "./trigger/myTask";
for await (const run of runs.subscribeToRun(runId)) {
diff --git a/docs/runs/max-duration.mdx b/docs/runs/max-duration.mdx
index 4b4872eee0..643cc53318 100644
--- a/docs/runs/max-duration.mdx
+++ b/docs/runs/max-duration.mdx
@@ -9,7 +9,7 @@ The `maxDuration` parameter sets a maximum compute time limit for tasks. When a
You must set a default maxDuration in your `trigger.config.ts` file, which will apply to all tasks unless overridden:
```ts /config/trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "proj_gtcwttqhhtlasxgfuhxs",
@@ -38,7 +38,7 @@ The `maxDuration` is set in seconds, and is compared to the CPU time elapsed sin
You can inspect the CPU time of a task inside the run function with our `usage` utility:
```ts /trigger/max-duration.ts
-import { task, usage } from "@trigger.dev/sdk/v3";
+import { task, usage } from "@trigger.dev/sdk";
export const maxDurationTask = task({
id: "max-duration-task",
@@ -60,7 +60,7 @@ The above value will be compared to the `maxDuration` you set. If the task excee
You can set a `maxDuration` on a specific task:
```ts /trigger/max-duration-task.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const maxDurationTask = task({
id: "max-duration-task",
@@ -76,7 +76,7 @@ This will override the default `maxDuration` set in the config file. If you have
You can "turn off" the Max duration set in your config file for a specific task like so:
```ts /trigger/max-duration-task.ts
-import { task, timeout } from "@trigger.dev/sdk/v3";
+import { task, timeout } from "@trigger.dev/sdk";
export const maxDurationTask = task({
id: "max-duration-task",
@@ -107,7 +107,7 @@ You can also set the `maxDuration` to `timeout.None` to turn off the max duratio
```ts /trigger/max-duration.ts
import { maxDurationTask } from "./trigger/max-duration-task";
-import { timeout } from "@trigger.dev/sdk/v3";
+import { timeout } from "@trigger.dev/sdk";
// Trigger the task with no maxDuration
const run = await maxDurationTask.trigger(
@@ -123,7 +123,7 @@ const run = await maxDurationTask.trigger(
You can access the `maxDuration` set for a run in the run context:
```ts /trigger/max-duration-task.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const maxDurationTask = task({
id: "max-duration-task",
diff --git a/docs/runs/metadata.mdx b/docs/runs/metadata.mdx
index 87c648b9a0..be601fbee2 100644
--- a/docs/runs/metadata.mdx
+++ b/docs/runs/metadata.mdx
@@ -20,7 +20,7 @@ const handle = await myTask.trigger(
You can get the current metadata at any time by calling `metadata.get()` or `metadata.current()` (only inside a run):
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -39,7 +39,7 @@ export const myTask = task({
Any of these methods can be called anywhere "inside" the run function, or a function called from the run function:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -57,7 +57,7 @@ async function doSomeWork() {
If you call any of the metadata methods outside of the run function, they will have no effect:
```ts
-import { metadata } from "@trigger.dev/sdk/v3";
+import { metadata } from "@trigger.dev/sdk";
// Somewhere outside of the run function
function doSomeWork() {
@@ -77,7 +77,7 @@ These methods also work inside any task lifecycle hook, either attached to the s
```ts myTasks.ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -94,7 +94,7 @@ export const myTask = task({
```
```ts trigger.config.ts
-import { defineConfig, metadata } from "@trigger.dev/sdk/v3";
+import { defineConfig, metadata } from "@trigger.dev/sdk";
export default defineConfig({
project: "proj_1234",
@@ -117,7 +117,7 @@ All metadata update methods (accept for `flush` and `stream`) are synchronous an
Set the value of a key in the metadata object:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -139,7 +139,7 @@ export const myTask = task({
Delete a key from the metadata object:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -161,7 +161,7 @@ export const myTask = task({
Replace the entire metadata object with a new object:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -180,7 +180,7 @@ export const myTask = task({
Append a value to an array in the metadata object:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -201,7 +201,7 @@ export const myTask = task({
Remove a value from an array in the metadata object:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -225,7 +225,7 @@ export const myTask = task({
Increment a numeric value in the metadata object:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -246,7 +246,7 @@ export const myTask = task({
Decrement a numeric value in the metadata object:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -267,7 +267,7 @@ export const myTask = task({
Capture a stream of values and make the stream available when using Realtime. See our [Realtime streams](/realtime/streams) documentation for more information.
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -295,7 +295,7 @@ export const myTask = task({
`metadata.stream` accepts any `AsyncIterable` or `ReadableStream` object. The stream will be captured and made available in the Realtime API. So for example, you could pass the body of a fetch response to `metadata.stream` to capture the response body and make it available in Realtime:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -329,7 +329,7 @@ export const myTask = task({
Or the results of a streaming call to the OpenAI SDK:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
import OpenAI from "openai";
const openai = new OpenAI({
@@ -365,7 +365,7 @@ export const myTask = task({
Flush the metadata to the database. The SDK will automatically flush the metadata periodically, so you don't need to call this method unless you need to ensure that the metadata is persisted immediately.
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -384,7 +384,7 @@ export const myTask = task({
All of the update methods can be chained together in a fluent API:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -405,7 +405,7 @@ Tasks that have been triggered by a parent task (a.k.a. a "child task") can upda
To update the parent task's metadata, use the `metadata.parent` accessor:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myParentTask = task({
id: "my-parent-task",
@@ -461,7 +461,7 @@ An example of where you might use parent and root updates is in a task that trig
```ts
import { CSVRow, UploadedFileData, parseCSVFromUrl } from "@/utils";
-import { batch, logger, metadata, schemaTask } from "@trigger.dev/sdk/v3";
+import { batch, logger, metadata, schemaTask } from "@trigger.dev/sdk";
export const handleCSVRow = schemaTask({
id: "handle-csv-row",
@@ -519,7 +519,7 @@ Combined with [Realtime](/realtime), you could use this to show a live progress
Metadata is NOT propagated to child tasks. If you want to pass metadata to a child task, you must do so explicitly:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -570,7 +570,7 @@ const handle = await myTask.trigger(
We recommend wrapping the metadata API in a [Zod](https://zod.dev) schema (or your validator library of choice) to provide type safety:
```ts
-import { task, metadata } from "@trigger.dev/sdk/v3";
+import { task, metadata } from "@trigger.dev/sdk";
import { z } from "zod";
const Metadata = z.object({
@@ -613,7 +613,7 @@ You can view the metadata for a run in the Trigger.dev dashboard. The metadata w
You can use the `runs.retrieve()` SDK function to get the metadata for a run:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
const run = await runs.retrieve("run_1234");
diff --git a/docs/runs/priority.mdx b/docs/runs/priority.mdx
new file mode 100644
index 0000000000..20da189462
--- /dev/null
+++ b/docs/runs/priority.mdx
@@ -0,0 +1,31 @@
+---
+title: "Priority"
+description: "Specify a priority when triggering a run."
+---
+
+You can set a priority when you trigger a run. This allows you to prioritize some of your runs over others, so they are started sooner. This is very useful when:
+
+- You have critical work that needs to start more quickly (and you have long queues).
+- You want runs for your premium users to take priority over free users.
+
+The value for priority is a time offset in seconds that determines the order of dequeuing.
+
+
+
+If you specify a priority of `10` the run will dequeue before runs that were triggered with no priority 8 seconds ago, like in this example:
+
+```ts
+// no priority = 0
+await myTask.trigger({ foo: "bar" });
+
+//... imagine 8s pass by
+
+// this run will start before the run above that was triggered 8s ago (with no priority)
+await myTask.trigger({ foo: "bar" }, { priority: 10 });
+```
+
+If you passed a value of `3600` the run would dequeue before runs that were triggered an hour ago (with no priority).
+
+
+ Setting a high priority will not allow you to beat runs from other organizations. It will only affect the order of your own runs.
+
diff --git a/docs/self-hosting/docker.mdx b/docs/self-hosting/docker.mdx
index ef2c7d6e85..c6856d348d 100644
--- a/docs/self-hosting/docker.mdx
+++ b/docs/self-hosting/docker.mdx
@@ -102,7 +102,7 @@ docker compose logs -f webapp
6. (optional) To initialize a new project, run the following command:
```bash
-npx trigger.dev@v4-beta init -p -a http://localhost:8030
+npx trigger.dev@latest init -p -a http://localhost:8030
```
@@ -349,16 +349,12 @@ TRIGGER_IMAGE_TAG=v4.0.0-v4-beta.21
This section highlights some of the CLI commands and options that are useful when self-hosting. Please check the [CLI reference](/cli-introduction) for more in-depth documentation.
-
-While v4 is in beta, always use `@v4-beta` instead of `@latest`. For example: `npx trigger.dev@v4-beta dev`
-
-
### Login
To avoid being redirected to [Trigger.dev Cloud](https://cloud.trigger.dev) when using the CLI, you need to specify the URL of your self-hosted instance with the `--api-url` or `-a` flag. For example:
```bash
-npx trigger.dev@v4-beta login -a http://trigger.example.com
+npx trigger.dev@latest login -a http://trigger.example.com
```
Once you've logged in, you shouldn't have to specify the URL again with other commands.
@@ -368,7 +364,7 @@ Once you've logged in, you shouldn't have to specify the URL again with other co
You can specify a profile when logging in. This allows you to easily use the CLI with multiple instances of Trigger.dev. For example:
```bash
-npx trigger.dev@v4-beta login -a http://trigger.example.com \
+npx trigger.dev@latest login -a http://trigger.example.com \
--profile self-hosted
```
@@ -377,29 +373,29 @@ Logging in with a new profile will also make it the new default profile.
To use a specific profile, you can use the `--profile` flag with other commands:
```bash
-npx trigger.dev@v4-beta dev --profile self-hosted
+npx trigger.dev@latest dev --profile self-hosted
```
To list all your profiles, use the `list-profiles` command:
```bash
-npx trigger.dev@v4-beta list-profiles
+npx trigger.dev@latest list-profiles
```
To remove a profile, use the `logout` command:
```bash
-npx trigger.dev@v4-beta logout --profile self-hosted
+npx trigger.dev@latest logout --profile self-hosted
```
To switch to a different profile, use the `switch` command:
```bash
# To run interactively
-npx trigger.dev@v4-beta switch
+npx trigger.dev@latest switch
# To switch to a specific profile
-npx trigger.dev@v4-beta switch self-hosted
+npx trigger.dev@latest switch self-hosted
```
### Whoami
@@ -407,7 +403,7 @@ npx trigger.dev@v4-beta switch self-hosted
It can be useful to check you are logged into the correct instance. Running this will also show the API URL:
```bash
-npx trigger.dev@v4-beta whoami
+npx trigger.dev@latest whoami
```
## CI / GitHub Actions
diff --git a/docs/snippets/bundle-packages.mdx b/docs/snippets/bundle-packages.mdx
index a4477b5b54..52676c5fdf 100644
--- a/docs/snippets/bundle-packages.mdx
+++ b/docs/snippets/bundle-packages.mdx
@@ -4,7 +4,7 @@
Bundle all ESM packages so that you don't have to specifiy them manually like this:
```ts trigger.config.ts
- import type { TriggerConfig } from "@trigger.dev/sdk/v3";
+ import type { TriggerConfig } from "@trigger.dev/sdk";
export const config: TriggerConfig = {
//..other stuff
@@ -18,7 +18,7 @@
Bundle individual packages using strings or regex like this:
```ts trigger.config.ts
- import type { TriggerConfig } from "@trigger.dev/sdk/v3";
+ import type { TriggerConfig } from "@trigger.dev/sdk";
export const config: TriggerConfig = {
//..other stuff
diff --git a/docs/snippets/code/openai-retry.mdx b/docs/snippets/code/openai-retry.mdx
index a0ad35affb..beb386e812 100644
--- a/docs/snippets/code/openai-retry.mdx
+++ b/docs/snippets/code/openai-retry.mdx
@@ -1,5 +1,5 @@
```ts /trigger/openai.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
import OpenAI from "openai";
const openai = new OpenAI({
diff --git a/docs/snippets/migrate-v4-using-ai.mdx b/docs/snippets/migrate-v4-using-ai.mdx
new file mode 100644
index 0000000000..4fc43687e0
--- /dev/null
+++ b/docs/snippets/migrate-v4-using-ai.mdx
@@ -0,0 +1,217 @@
+
+
+I would like you to help me migrate my v3 task code to v4. Here are the important differences:
+
+We've deprecated the `@trigger.dev/sdk/v3` import path and moved to a new path:
+
+```ts
+// This is the old path
+import { task } from "@trigger.dev/sdk/v3";
+
+// This is the new path, use this instead
+import { task } from "@trigger.dev/sdk";
+```
+
+We've renamed the `handleError` hook to `catchError`. Use this instead of `handleError`.
+
+`init` was previously used to initialize data used in the run function. This is the old version:
+
+```ts
+import { task } from "@trigger.dev/sdk";
+
+const myTask = task({
+ init: async () => {
+ return {
+ myClient: new MyClient(),
+ };
+ },
+ run: async (payload: any, { ctx, init }) => {
+ const client = init.myClient;
+ await client.doSomething();
+ },
+});
+```
+
+This is the new version using middleware and locals:
+
+```ts
+import { task, locals, tasks } from "@trigger.dev/sdk";
+
+// Create a local for your client
+const MyClientLocal = locals.create("myClient");
+
+// Set up middleware to initialize the client
+tasks.middleware("my-client", async ({ next }) => {
+ const client = new MyClient();
+ locals.set(MyClientLocal, client);
+ await next();
+});
+
+// Helper function to get the client
+function getMyClient() {
+ return locals.getOrThrow(MyClientLocal);
+}
+
+const myTask = task({
+ run: async (payload: any, { ctx }) => {
+ const client = getMyClient();
+ await client.doSomething();
+ },
+});
+```
+
+We’ve deprecated the `toolTask` function and replaced it with the `ai.tool` function, which creates an AI tool from an existing `schemaTask`. This is the old version:
+
+```ts
+import { toolTask, schemaTask } from "@trigger.dev/sdk";
+import { z } from "zod";
+import { generateText } from "ai";
+
+const myToolTask = toolTask({
+ id: "my-tool-task",
+ run: async (payload: any, { ctx }) => {},
+});
+
+export const myAiTask = schemaTask({
+ id: "my-ai-task",
+ schema: z.object({
+ text: z.string(),
+ }),
+ run: async (payload, { ctx }) => {
+ const { text } = await generateText({
+ prompt: payload.text,
+ model: openai("gpt-4o"),
+ tools: {
+ myToolTask,
+ },
+ });
+ },
+});
+```
+
+This is the new version:
+
+```ts
+import { schemaTask, ai } from "@trigger.dev/sdk";
+import { z } from "zod";
+import { generateText } from "ai";
+
+// Convert toolTask to schemaTask with a schema
+const myToolTask = schemaTask({
+ id: "my-tool-task",
+ schema: z.object({
+ // Add appropriate schema for your tool's payload
+ input: z.string(),
+ }),
+ run: async (payload, { ctx }) => {},
+});
+
+// Create an AI tool from the schemaTask
+const myTool = ai.tool(myToolTask);
+
+export const myAiTask = schemaTask({
+ id: "my-ai-task",
+ schema: z.object({
+ text: z.string(),
+ }),
+ run: async (payload, { ctx }) => {
+ const { text } = await generateText({
+ prompt: payload.text,
+ model: openai("gpt-4o"),
+ tools: {
+ myTool, // Use the ai.tool created from schemaTask
+ },
+ });
+ },
+});
+```
+
+We've made several breaking changes that require code updates:
+
+**Queue changes**: Queues must now be defined ahead of time using the `queue` function. You can no longer create queues "on-demand" when triggering tasks. This is the old version:
+
+```ts
+// Old v3 way - creating queue on-demand
+await myTask.trigger({ foo: "bar" }, { queue: { name: "my-queue", concurrencyLimit: 10 } });
+```
+
+This is the new version:
+
+```ts
+// New v4 way - define queue first
+import { queue, task } from "@trigger.dev/sdk";
+
+const myQueue = queue({
+ name: "my-queue",
+ concurrencyLimit: 10,
+});
+
+export const myTask = task({
+ id: "my-task",
+ queue: myQueue, // Set queue on task
+ run: async (payload: any, { ctx }) => {},
+});
+
+// Now trigger without queue options
+await myTask.trigger({ foo: "bar" });
+
+// Or specify queue by name
+await myTask.trigger({ foo: "bar" }, { queue: "my-queue" });
+```
+
+**Lifecycle hooks**: Function signatures have changed to use a single object parameter instead of separate parameters. This is the old version:
+
+```ts
+// Old v3 way
+export const myTask = task({
+ id: "my-task",
+ onStart: (payload, { ctx }) => {},
+ onSuccess: (payload, output, { ctx }) => {},
+ onFailure: (payload, error, { ctx }) => {},
+ catchError: (payload, { ctx, error, retry }) => {},
+ run: async (payload, { ctx }) => {},
+});
+```
+
+This is the new version:
+
+```ts
+// New v4 way - single object parameter for hooks
+export const myTask = task({
+ id: "my-task",
+ onStart: ({ payload, ctx }) => {},
+ onSuccess: ({ payload, output, ctx }) => {},
+ onFailure: ({ payload, error, ctx }) => {},
+ catchError: ({ payload, ctx, error, retry }) => {},
+ run: async (payload, { ctx }) => {}, // run function unchanged
+});
+```
+
+**BatchTrigger changes**: The `batchTrigger` function no longer returns runs directly. This is the old version:
+
+```ts
+// Old v3 way
+const batchHandle = await tasks.batchTrigger([
+ [myTask, { foo: "bar" }],
+ [myOtherTask, { baz: "qux" }],
+]);
+
+console.log(batchHandle.runs); // Direct access
+```
+
+This is the new version:
+
+```ts
+// New v4 way
+const batchHandle = await tasks.batchTrigger([
+ [myTask, { foo: "bar" }],
+ [myOtherTask, { baz: "qux" }],
+]);
+
+const runs = await batchHandle.runs.list(); // Use runs.list()
+console.log(runs);
+```
+
+Can you help me convert the following code from v3 to v4? Please include the full converted code in the answer, do not truncate it anywhere.
+
+
\ No newline at end of file
diff --git a/docs/snippets/run-boolean-helpers.mdx b/docs/snippets/run-boolean-helpers.mdx
new file mode 100644
index 0000000000..48aac6ae11
--- /dev/null
+++ b/docs/snippets/run-boolean-helpers.mdx
@@ -0,0 +1,7 @@
+- **`isQueued`**: Returns `true` when the status is `QUEUED`, `PENDING_VERSION`, or `DELAYED`
+- **`isExecuting`**: Returns `true` when the status is `EXECUTING` or `DEQUEUED`. These count against your concurrency limits.
+- **`isWaiting`**: Returns `true` when the status is `WAITING`. These do not count against your concurrency limits.
+- **`isCompleted`**: Returns `true` when the status is any of the completed statuses
+- **`isCanceled`**: Returns `true` when the status is `CANCELED`
+- **`isFailed`**: Returns `true` when the status is any of the failed statuses
+- **`isSuccess`**: Returns `true` when the status is `COMPLETED`
\ No newline at end of file
diff --git a/docs/snippets/upgrade-to-v4-note.mdx b/docs/snippets/upgrade-to-v4-note.mdx
deleted file mode 100644
index 70ce8a405e..0000000000
--- a/docs/snippets/upgrade-to-v4-note.mdx
+++ /dev/null
@@ -1,4 +0,0 @@
-
- This feature is only available in the v4 beta. To upgrade to v4, see the [upgrade to v4
- docs](/upgrade-to-v4).
-
diff --git a/docs/tags.mdx b/docs/tags.mdx
index dcc3b438c6..66b66a010e 100644
--- a/docs/tags.mdx
+++ b/docs/tags.mdx
@@ -60,7 +60,7 @@ This will create a run with the tags `user_123456` and `org_abcdefg`. They look
Use the `tags.add()` function to add tags to a run from inside the `run` function. This will add the tag `product_1234567` to the run:
```ts
-import { task, tags } from "@trigger.dev/sdk/v3";
+import { task, tags } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -111,7 +111,7 @@ On the Runs page open the filter menu, choose "Tags" and then start typing in th
You can provide filters to the `runs.list` SDK function, including an array of tags.
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
// Loop through all runs with the tag "user_123456" that have completed
for await (const run of runs.list({ tag: "user_123456", status: ["COMPLETED"] })) {
diff --git a/docs/tasks/overview.mdx b/docs/tasks/overview.mdx
index 4682cdc643..aa305f2f80 100644
--- a/docs/tasks/overview.mdx
+++ b/docs/tasks/overview.mdx
@@ -11,24 +11,19 @@ There are different types of tasks including regular tasks and [scheduled tasks]
Here's an incredibly simple task:
```ts /trigger/hello-world.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
-//1. You need to export each task, even if it's a subtask
-export const helloWorld = task({
- //2. Use a unique id for each task
+const helloWorld = task({
+ //1. Use a unique id for each task
id: "hello-world",
- //3. The run function is the main function of the task
+ //2. The run function is the main function of the task
run: async (payload: { message: string }) => {
- //4. You can write code that runs for a long time here, there are no timeouts
+ //3. You can write code that runs for a long time here, there are no timeouts
console.log(payload.message);
},
});
```
-
- You must `export` each task, even subtasks inside the same file. When exported they are accessible so their configuration can be registered with the platform.
-
-
You can trigger this in two ways:
1. From the dashboard [using the "Test" feature](/run-tests).
@@ -141,6 +136,40 @@ export const longTask = task({
See our [maxDuration guide](/runs/max-duration) for more information.
+## Global lifecycle hooks
+
+When specifying global lifecycle hooks, we recommend using the `init.ts` file.
+
+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
+import { tasks } from "@trigger.dev/sdk";
+
+tasks.onStart(({ ctx, payload, task }) => {
+ console.log("Run started", ctx.run);
+});
+
+tasks.onSuccess(({ ctx, output }) => {
+ console.log("Run finished", ctx.run);
+});
+
+tasks.onFailure(({ ctx, error }) => {
+ console.log("Run failed", ctx.run);
+});
+```
+
+### `init.ts`
+
+If you create a `init.ts` file at the root of your trigger directory, it will be automatically loaded when a task is executed. This is useful if you want to register global lifecycle hooks, or initialize a database connection, etc.
+
+```ts init.ts
+import { tasks } from "@trigger.dev/sdk";
+
+tasks.onStart(({ ctx, payload, task }) => {
+ console.log("Run started", ctx.run);
+});
+```
+
## Lifecycle functions

@@ -195,15 +224,78 @@ export const taskWithCleanup = task({
Errors thrown in the `cleanup` function will fail the attempt.
-### `middleware` function
+### `middleware` and `locals` functions
-This function is called before the `run` function, it allows you to wrap the run function with custom code.
+Our task middleware system runs at the top level, executing before and after all lifecycle hooks. This allows you to wrap the entire task execution lifecycle with custom logic.
An error thrown in `middleware` is just like an uncaught error in the run function: it will
propagate through to `handleError()` and then will fail the attempt (causing a retry).
+The `locals` API allows you to share data between middleware and hooks.
+
+```ts db.ts
+import { locals } from "@trigger.dev/sdk";
+import { logger, tasks } from "@trigger.dev/sdk";
+
+// This would be type of your database client here
+const DbLocal = locals.create<{ connect: () => Promise; disconnect: () => Promise }>(
+ "db"
+);
+
+export function getDb() {
+ return locals.getOrThrow(DbLocal);
+}
+
+export function setDb(db: { connect: () => Promise }) {
+ locals.set(DbLocal, db);
+}
+
+tasks.middleware("db", async ({ ctx, payload, next, task }) => {
+ // This would be your database client here
+ const db = locals.set(DbLocal, {
+ connect: async () => {
+ logger.info("Connecting to the database");
+ },
+ disconnect: async () => {
+ logger.info("Disconnecting from the database");
+ },
+ });
+
+ await db.connect();
+
+ await next();
+
+ await db.disconnect();
+});
+
+// Disconnect when the run is paused
+tasks.onWait("db", async ({ ctx, payload, task }) => {
+ const db = getDb();
+ await db.disconnect();
+});
+
+// Reconnect when the run is resumed
+tasks.onResume("db", async ({ ctx, payload, task }) => {
+ const db = getDb();
+ await db.connect();
+});
+```
+
+You can access the database client using `getDb()` in your tasks `run` function and all your hooks (global or task specific):
+
+```ts
+import { getDb } from "./db";
+
+export const myTask = task({
+ run: async (payload: any, { ctx }) => {
+ const db = getDb();
+ await db.query("SELECT 1");
+ },
+});
+```
+
### `onStart` function
When a task run starts, the `onStart` function is called. It's useful for sending notifications, logging, and other side effects. This function will only be called one per run (not per retry). If you want to run code before each retry, use the `init` function.
@@ -223,7 +315,7 @@ export const taskWithOnStart = task({
You can also define an `onStart` function in your `trigger.config.ts` file to get notified when any task starts.
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "proj_1234",
@@ -235,6 +327,29 @@ export default defineConfig({
Errors thrown in the `onStart` function are ignored.
+### `onWait` and `onResume` functions
+
+These lifecycle hooks allow you to run code when a run is paused or resumed because of a wait:
+
+```ts
+export const myTask = task({
+ id: "my-task",
+ onWait: async ({ wait }) => {
+ console.log("Run paused", wait);
+ },
+ onResume: async ({ wait }) => {
+ console.log("Run resumed", wait);
+ },
+ run: async (payload: any, { ctx }) => {
+ console.log("Run started", ctx.run);
+
+ await wait.for({ seconds: 10 });
+
+ console.log("Run finished", ctx.run);
+ },
+});
+```
+
### `onSuccess` function
When a task run succeeds, the `onSuccess` function is called. It's useful for sending notifications, logging, syncing state to your database, or other side effects.
@@ -254,7 +369,7 @@ export const taskWithOnSuccess = task({
You can also define an `onSuccess` function in your `trigger.config.ts` file to get notified when any task succeeds.
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "proj_1234",
@@ -266,6 +381,22 @@ export default defineConfig({
Errors thrown in the `onSuccess` function are ignored.
+### `onComplete` function
+
+This hook is executed when a run completes, regardless of whether it succeeded or failed:
+
+```ts /trigger/on-complete.ts
+export const taskWithOnComplete = task({
+ id: "task-with-on-complete",
+ onComplete: async (payload, output, { ctx }) => {
+ if (result.ok) {
+ console.log("Run succeeded", result.data);
+ } else {
+ console.log("Run failed", result.error);
+ }
+});
+```
+
### `onFailure` function
When a task run fails, the `onFailure` function is called. It's useful for sending notifications, logging, or other side effects. It will only be executed once the task run has exhausted all its retries.
@@ -285,7 +416,7 @@ export const taskWithOnFailure = task({
You can also define an `onFailure` function in your `trigger.config.ts` file to get notified when any task fails.
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "proj_1234",
@@ -309,6 +440,105 @@ Read more about `handleError` in our [Errors and Retrying guide](/errors-retryin
Uncaught errors will throw a special internal error of the type `HANDLE_ERROR_ERROR`.
+### onCancel
+
+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
+tasks.onCancel(({ ctx, signal }) => {
+ console.log("Run cancelled", 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
+import { logger, tasks, schemaTask } from "@trigger.dev/sdk";
+import { streamText } from "ai";
+import { z } from "zod";
+
+export const interruptibleChat = schemaTask({
+ id: "interruptible-chat",
+ description: "Chat with the AI",
+ schema: z.object({
+ prompt: z.string().describe("The prompt to chat with the AI"),
+ }),
+ run: async ({ prompt }, { signal }) => {
+ const chunks: TextStreamPart<{}>[] = [];
+
+ // 👇 This is a global onCancel hook, but it's inside of the run function
+ tasks.onCancel(async () => {
+ // We have access to the chunks here, and can save them to the database
+ await saveChunksToDatabase(chunks);
+ });
+
+ try {
+ const result = streamText({
+ model: getModel(),
+ prompt,
+ experimental_telemetry: {
+ isEnabled: true,
+ },
+ tools: {},
+ abortSignal: signal, // 👈 Pass the signal to the streamText function, which aborts with the run is cancelled
+ onChunk: ({ chunk }) => {
+ chunks.push(chunk);
+ },
+ });
+
+ const textParts = [];
+
+ for await (const part of result.textStream) {
+ textParts.push(part);
+ }
+
+ return textParts.join("");
+ } catch (error) {
+ if (error instanceof Error && error.name === "AbortError") {
+ // streamText will throw an AbortError if the signal is aborted, so we can handle it here
+ } else {
+ throw error;
+ }
+ }
+ },
+});
+```
+
+The `onCancel` hook can optionally wait for the `run` function to finish, and access the output of the run:
+
+```ts
+import { logger, task } from "@trigger.dev/sdk";
+import { setTimeout } from "node:timers/promises";
+
+export const cancelExampleTask = task({
+ id: "cancel-example",
+ // Signal will be aborted when the task is cancelled 👇
+ run: async (payload: { message: string }, { signal }) => {
+ try {
+ // We pass the signal to setTimeout to abort the timeout if the task is cancelled
+ await setTimeout(10_000, undefined, { signal });
+ } catch (error) {
+ // Ignore the abort error
+ }
+
+ // Do some more work here
+
+ return {
+ message: "Hello, world!",
+ };
+ },
+ onCancel: async ({ runPromise }) => {
+ // You can await the runPromise to get the output of the task
+ const output = await runPromise;
+ },
+});
+```
+
+
+ You will have up to 30 seconds to complete the `runPromise` in the `onCancel` hook. After that
+ point the process will be killed.
+
+
## Next steps
diff --git a/docs/tasks/scheduled.mdx b/docs/tasks/scheduled.mdx
index aea6efb9db..b1e501494c 100644
--- a/docs/tasks/scheduled.mdx
+++ b/docs/tasks/scheduled.mdx
@@ -10,7 +10,7 @@ description: "A task that is triggered on a recurring schedule using cron syntax
This task will run when any of the attached schedules trigger. They have a predefined payload with some useful properties:
```ts
-import { schedules } from "@trigger.dev/sdk/v3";
+import { schedules } from "@trigger.dev/sdk";
export const firstScheduledTask = schedules.task({
id: "first-scheduled-task",
@@ -227,7 +227,7 @@ By using the `externalId` you can have schedules for your users. This is useful
A reminder task:
```ts /trigger/reminder.ts
-import { schedules } from "@trigger.dev/sdk/v3";
+import { schedules } from "@trigger.dev/sdk";
//this task will run when any of the attached schedules trigger
export const reminderTask = schedules.task({
diff --git a/docs/tasks/schemaTask.mdx b/docs/tasks/schemaTask.mdx
index 5f28ebe2cd..3692d1d703 100644
--- a/docs/tasks/schemaTask.mdx
+++ b/docs/tasks/schemaTask.mdx
@@ -9,7 +9,7 @@ The `schemaTask` function allows you to define a task with a runtime payload sch
## Usage
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { z } from "zod";
const myTask = schemaTask({
@@ -34,7 +34,7 @@ const myTask = schemaTask({
When you trigger the task directly, the payload will be validated against the schema before the [run](/runs) is created:
```ts
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import { myTask } from "./trigger/myTasks";
// This will call the schema parser function and validate the payload
@@ -53,7 +53,7 @@ We will also validate the payload every time before the task is run, so you can
Certain schema libraries, like Zod, split their type inference into "schema in" and "schema out". This means that you can define a single schema that will produce different types when triggering the task and when running the task. For example, you can define a schema that has a default value for a field, or a string coerced into a date:
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { z } from "zod";
const myTask = schemaTask({
@@ -76,6 +76,138 @@ await myTask.trigger({ age: 30, dob: "2020-01-01" }); // this is valid
await myTask.trigger({ name: "Alice", age: 30, dob: "2020-01-01" }); // this is also valid
```
+## `ai.tool`
+
+The `ai.tool` function allows you to create an AI tool from an existing `schemaTask` to use with the Vercel [AI SDK](https://vercel.com/docs/ai-sdk):
+
+```ts
+import { ai } from "@trigger.dev/sdk/ai";
+import { schemaTask } from "@trigger.dev/sdk";
+import { z } from "zod";
+import { generateText } from "ai";
+
+const myToolTask = schemaTask({
+ id: "my-tool-task",
+ schema: z.object({
+ foo: z.string(),
+ }),
+ run: async (payload: any, { ctx }) => {},
+});
+
+const myTool = ai.tool(myToolTask);
+
+export const myAiTask = schemaTask({
+ id: "my-ai-task",
+ schema: z.object({
+ text: z.string(),
+ }),
+ run: async (payload, { ctx }) => {
+ const { text } = await generateText({
+ prompt: payload.text,
+ model: openai("gpt-4o"),
+ tools: {
+ myTool,
+ },
+ });
+ },
+});
+```
+
+You can also pass the `experimental_toToolResultContent` option to the `ai.tool` function to customize the content of the tool result:
+
+```ts
+import { openai } from "@ai-sdk/openai";
+import { Sandbox } from "@e2b/code-interpreter";
+import { ai } from "@trigger.dev/sdk/ai";
+import { schemaTask } from "@trigger.dev/sdk";
+import { generateObject } from "ai";
+import { z } from "zod";
+
+const chartTask = schemaTask({
+ id: "chart",
+ description: "Generate a chart using natural language",
+ schema: z.object({
+ input: z.string().describe("The chart to generate"),
+ }),
+ run: async ({ input }) => {
+ const code = await generateObject({
+ model: openai("gpt-4o"),
+ schema: z.object({
+ code: z.string().describe("The Python code to execute"),
+ }),
+ system: `
+ You are a helpful assistant that can generate Python code to be executed in a sandbox, using matplotlib.pyplot.
+
+ For example:
+
+ import matplotlib.pyplot as plt
+ plt.plot([1, 2, 3, 4])
+ plt.ylabel('some numbers')
+ plt.show()
+
+ Make sure the code ends with plt.show()
+ `,
+ prompt: input,
+ });
+
+ const sandbox = await Sandbox.create();
+
+ const execution = await sandbox.runCode(code.object.code);
+
+ const firstResult = execution.results[0];
+
+ if (firstResult.png) {
+ return {
+ chart: firstResult.png,
+ };
+ } else {
+ throw new Error("No chart generated");
+ }
+ },
+});
+
+// This is useful if you want to return an image from the tool
+export const chartTool = ai.tool(chartTask, {
+ experimental_toToolResultContent: (result) => {
+ return [
+ {
+ type: "image",
+ data: result.chart,
+ mimeType: "image/png",
+ },
+ ];
+ },
+});
+```
+
+You can access the current tool execution options inside the task run function using the `ai.currentToolOptions()` function:
+
+```ts
+import { ai } from "@trigger.dev/sdk/ai";
+import { schemaTask } from "@trigger.dev/sdk";
+import { z } from "zod";
+
+const myToolTask = schemaTask({
+ id: "my-tool-task",
+ schema: z.object({
+ foo: z.string(),
+ }),
+ run: async (payload, { ctx }) => {
+ const toolOptions = ai.currentToolOptions();
+ console.log(toolOptions);
+ },
+});
+
+export const myAiTask = ai.tool(myToolTask);
+```
+
+See the [AI SDK tool execution options docs](https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling#tool-execution-options) for more details on the tool execution options.
+
+
+ `ai.tool` is compatible with `schemaTask`'s defined with Zod and ArkType schemas, or any schemas
+ that implement a `.toJsonSchema()` function.
+
+
## Supported schema types
### Zod
@@ -83,7 +215,7 @@ await myTask.trigger({ name: "Alice", age: 30, dob: "2020-01-01" }); // this is
You can use the [Zod](https://zod.dev) schema library to define your schema. The schema will be validated using Zod's `parse` function.
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { z } from "zod";
export const zodTask = schemaTask({
@@ -101,7 +233,7 @@ export const zodTask = schemaTask({
### Yup
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import * as yup from "yup";
export const yupTask = schemaTask({
@@ -119,7 +251,7 @@ export const yupTask = schemaTask({
### Superstruct
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { object, string } from "superstruct";
export const superstructTask = schemaTask({
@@ -137,7 +269,7 @@ export const superstructTask = schemaTask({
### ArkType
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { type } from "arktype";
export const arktypeTask = schemaTask({
@@ -155,7 +287,7 @@ export const arktypeTask = schemaTask({
### @effect/schema
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import * as Schema from "@effect/schema/Schema";
// For some funny typescript reason, you cannot pass the Schema.decodeUnknownSync directly to schemaTask
@@ -175,7 +307,7 @@ export const effectTask = schemaTask({
### runtypes
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import * as T from "runtypes";
export const runtypesTask = schemaTask({
@@ -193,7 +325,7 @@ export const runtypesTask = schemaTask({
### valibot
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import * as v from "valibot";
@@ -217,7 +349,7 @@ export const valibotTask = schemaTask({
### typebox
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
import { Type } from "@sinclair/typebox";
import { wrap } from "@typeschema/typebox";
@@ -240,7 +372,7 @@ export const typeboxTask = schemaTask({
You can also define a custom parser function that will be called with the payload before the task is run. The parser function should return the parsed payload or throw an error if the payload is invalid.
```ts
-import { schemaTask } from "@trigger.dev/sdk/v3";
+import { schemaTask } from "@trigger.dev/sdk";
export const customParserTask = schemaTask({
id: "types/custom-parser",
diff --git a/docs/triggering.mdx b/docs/triggering.mdx
index 235383796f..fb07032954 100644
--- a/docs/triggering.mdx
+++ b/docs/triggering.mdx
@@ -46,7 +46,7 @@ Triggers a single run of a task with the payload you pass in, and any options yo
```ts Your backend
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { emailSequence } from "~/trigger/emails";
// 👆 **type-only** import
@@ -69,7 +69,7 @@ export async function POST(request: Request) {
You can pass in options to the task using the second argument:
```ts Your backend
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { emailSequence } from "~/trigger/emails";
//app/email/route.ts
@@ -97,7 +97,7 @@ export async function POST(request: Request) {
Triggers multiple runs of a single task with the payloads you pass in, and any options you specify, without needing to import the task.
```ts Your backend
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { emailSequence } from "~/trigger/emails";
// 👆 **type-only** import
@@ -120,7 +120,7 @@ export async function POST(request: Request) {
You can pass in options to the `batchTrigger` function using the second argument:
```ts Your backend
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { emailSequence } from "~/trigger/emails";
//app/email/route.ts
@@ -143,7 +143,7 @@ export async function POST(request: Request) {
You can also pass in options for each run in the batch:
```ts Your backend
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { emailSequence } from "~/trigger/emails";
//app/email/route.ts
@@ -173,7 +173,7 @@ Triggers a single run of a task with the payload you pass in, and any options yo
```ts Your backend
-import { tasks } from "@trigger.dev/sdk/v3";
+import { tasks } from "@trigger.dev/sdk";
import type { emailSequence } from "~/trigger/emails";
//app/email/route.ts
@@ -201,7 +201,7 @@ export async function POST(request: Request) {
Triggers multiple runs of different tasks with the payloads you pass in, and any options you specify. This is useful when you need to trigger multiple tasks at once.
```ts Your backend
-import { batch } from "@trigger.dev/sdk/v3";
+import { batch } from "@trigger.dev/sdk";
import type { myTask1, myTask2 } from "~/trigger/myTasks";
export async function POST(request: Request) {
@@ -238,7 +238,7 @@ Triggers a single run of a task with the payload you pass in, and any options yo
```ts ./trigger/my-task.ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
@@ -255,7 +255,7 @@ export const myTask = task({
To pass options to the triggered task, you can use the second argument:
```ts ./trigger/my-task.ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
@@ -274,7 +274,7 @@ export const myTask = task({
Triggers multiple runs of a single task with the payloads you pass in, and any options you specify.
```ts /trigger/my-task.ts
-import { batch } from "@trigger.dev/sdk/v3";
+import { batch } from "@trigger.dev/sdk";
import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
@@ -291,7 +291,7 @@ export const myTask = task({
If you need to pass options to `batchTrigger`, you can use the second argument:
```ts /trigger/my-task.ts
-import { batch } from "@trigger.dev/sdk/v3";
+import { batch } from "@trigger.dev/sdk";
import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
@@ -310,7 +310,7 @@ export const myTask = task({
You can also pass in options for each run in the batch:
```ts /trigger/my-task.ts
-import { batch } from "@trigger.dev/sdk/v3";
+import { batch } from "@trigger.dev/sdk";
import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
@@ -416,7 +416,7 @@ export const parentTask = task({
You can also catch the error if the child task fails and get more information about the error:
```ts /trigger/parent.ts
-import { task, SubtaskUnwrapError } from "@trigger.dev/sdk/v3";
+import { task, SubtaskUnwrapError } from "@trigger.dev/sdk";
export const parentTask = task({
id: "parent-task",
run: async (payload: string) => {
@@ -565,7 +565,7 @@ export const batchParentTask = task({
You can batch trigger multiple different tasks and wait for all the results:
```ts /trigger/batch.ts
-import { batch, task } from "@trigger.dev/sdk/v3";
+import { batch, task } from "@trigger.dev/sdk";
export const parentTask = task({
id: "parent-task",
@@ -614,7 +614,7 @@ export const childTask2 = task({
You can batch trigger multiple different tasks by passing in the task instances. This function is especially useful when you have a static set of tasks you want to trigger:
```ts /trigger/batch.ts
-import { batch, task, runs } from "@trigger.dev/sdk/v3";
+import { batch, task, runs } from "@trigger.dev/sdk";
export const parentTask = task({
id: "parent-task",
@@ -650,7 +650,7 @@ export const childTask2 = task({
You can batch trigger multiple different tasks by passing in the task instances, and wait for all the results. This function is especially useful when you have a static set of tasks you want to trigger:
```ts /trigger/batch.ts
-import { batch, task, runs } from "@trigger.dev/sdk/v3";
+import { batch, task, runs } from "@trigger.dev/sdk";
export const parentTask = task({
id: "parent-task",
@@ -748,7 +748,7 @@ Runs that are delayed and have not been enqueued yet will display in the dashboa
You can cancel a delayed run using the `runs.cancel` SDK function:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
await runs.cancel("run_1234");
```
@@ -756,7 +756,7 @@ await runs.cancel("run_1234");
You can also reschedule a delayed run using the `runs.reschedule` SDK function:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
// The delay option here takes the same format as the trigger delay option
await runs.reschedule("run_1234", { delay: "1h" });
@@ -813,7 +813,7 @@ For this reason, the `ttl` option only accepts durations and not absolute timest
You can provide an `idempotencyKey` to ensure that a task is only triggered once with the same key. This is useful if you are triggering a task within another task that might be retried:
```typescript
-import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, task } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -845,7 +845,7 @@ For more information, see our [Idempotency](/idempotency) documentation.
Idempotency keys automatically expire after 30 days, but you can set a custom TTL for an idempotency key when triggering a task:
```typescript
-import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
+import { idempotencyKeys, task } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
@@ -980,6 +980,10 @@ View our [metadata doc](/runs/metadata) for more information.
View our [maxDuration doc](/runs/max-duration) for more information.
+### `priority`
+
+View our [priority doc](/runs/priority) for more information.
+
## Large Payloads
We recommend keeping your task payloads as small as possible. We currently have a hard limit on task payloads above 10MB.
@@ -989,7 +993,7 @@ If your payload size is larger than 512KB, instead of saving the payload to the
When your task runs, we automatically download the payload from the object store and pass it to your task function. We also will return to you a `payloadPresignedUrl` from the `runs.retrieve` SDK function so you can download the payload if needed:
```ts
-import { runs } from "@trigger.dev/sdk/v3";
+import { runs } from "@trigger.dev/sdk";
const run = await runs.retrieve(handle);
@@ -1043,7 +1047,7 @@ const handle = await myTask.trigger({
```
```ts /trigger/myTasks.ts
-import { task } from "@trigger.dev/sdk/v3";
+import { task } from "@trigger.dev/sdk";
export const myTask = task({
id: "my-task",
diff --git a/docs/troubleshooting-alerts.mdx b/docs/troubleshooting-alerts.mdx
index b79ddb05cf..1d4322201b 100644
--- a/docs/troubleshooting-alerts.mdx
+++ b/docs/troubleshooting-alerts.mdx
@@ -42,7 +42,7 @@ For the alert webhooks you can use the SDK to parse them. Here is an example of
```ts
import { ActionFunctionArgs, json } from "@remix-run/server-runtime";
-import { webhooks, WebhookError } from "@trigger.dev/sdk/v3";
+import { webhooks, WebhookError } from "@trigger.dev/sdk";
export async function action({ request }: ActionFunctionArgs) {
// Make sure this is a POST request
diff --git a/docs/troubleshooting.mdx b/docs/troubleshooting.mdx
index ca0acb0726..30a5fe526f 100644
--- a/docs/troubleshooting.mdx
+++ b/docs/troubleshooting.mdx
@@ -78,7 +78,7 @@ Usually there will be some useful guidance below this message. If you can't figu
This happens because `.node` files are native code and can't be bundled like other packages. To fix this, add your package to [`build.external`](/config/config-file#external) in the `trigger.config.ts` file like this:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -105,7 +105,7 @@ TypeError: reactDOMServer.renderToPipeableStream is not a function
This happens because react-email packages have bundling conflicts with our build process. To fix this, add the react-email packages to your `external` build settings in your `trigger.config.ts` file:
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
diff --git a/docs/upgrade-to-v4.mdx b/docs/upgrade-to-v4.mdx
deleted file mode 100644
index 00b727021c..0000000000
--- a/docs/upgrade-to-v4.mdx
+++ /dev/null
@@ -1,1102 +0,0 @@
----
-title: "Upgrading to v4"
-description: "What's new in v4, how to upgrade, and breaking changes."
----
-
-import NodeVersions from "/snippets/node-versions.mdx";
-
-## What's new in v4?
-
-[Read our blog post](https://trigger.dev/blog/v4-beta-launch) for an overview of the new features.
-
-### Node.js support
-
-
-
-### Wait tokens
-
-In addition to waiting for a specific duration, or waiting for a child task to complete, you can now create and wait for a token to be completed, giving you more flexibility and the ability to wait for arbitrary conditions. For example, you can send the token to a Slack channel, and only complete the token when the user has clicked an "Approve" button.
-
-To wait for a token, you need to first create one using the `wait.createToken` function:
-
-```ts
-import { wait } from "@trigger.dev/sdk";
-
-// Somewhere in your code, either your backend or inside a task
-const token = await wait.createToken({
- timeout: "10m", // you can optionally specify a timeout for the token
-});
-
-await sendTokenToSlack(token.id);
-```
-
-Wait tokens are completed with a payload that you can specify when you complete the token:
-
-```ts
-// When the user clicks the "Approve" button, you can complete the token
-await wait.completeToken(tokenId, {
- status: "approved",
-});
-```
-
-You can wait for the token using the token ID:
-
-```ts
-type ApprovalToken = {
- status: "approved" | "rejected";
-};
-
-// Inside a task
-const result = await wait.forToken(tokenId);
-
-if (result.ok) {
- console.log("Token completed", result.output.status); // "approved" or "rejected"
-} else {
- console.log("Token timed out", result.error);
-}
-```
-
-### Wait idempotency
-
-You can now pass an idempotency key to any wait function, allowing you to skip waits if the same idempotency key is used again. This can be useful if you want to skip waits when retrying a task, for example:
-
-```ts
-// Specify the idempotency key and TTL when creating a wait token
-const token = await wait.createToken({
- idempotencyKey: "my-idempotency-key",
- idempotencyKeyTTL: "1h",
-});
-
-// Specify the idempotency key and TTL when waiting for a duration:
-await wait.for({ seconds: 10 }, { idempotencyKey: "my-idempotency-key", idempotencyKeyTTL: "1h" });
-
-// Specify the idempotency key and TTL when waiting for a child task:
-await childTask.triggerAndWait(
- { foo: "bar" },
- {
- idempotencyKey: "my-idempotency-key",
- idempotencyKeyTTL: "1h",
- }
-);
-```
-
-`idempotencyKeyTTL` allows you to specify how long the idempotency key should be valid for. The default is 30 days.
-
-### Priority
-
-You can now specify a priority when triggering a task. This allows you to prioritize certain tasks over others, and is useful if you want to ensure that certain tasks are executed before others.
-
-```ts
-await task.trigger({ foo: "bar" }, { priority: 1 });
-```
-
-The priority value is a time duration in seconds, which offsets the timestamp of the run in the queue. If you specify a priority of `10`, the run will win over runs with a priority of `0` that were triggered within the last 10 seconds. A more concrete example:
-
-```ts
-// Triggered at 12:00:00, into a queue with a large number of queued runs
-await task.trigger({ foo: "bar" }, { priority: 0 });
-// Triggered at 12:00:09, into the same queue
-await task.trigger({ foo: "bar" }, { priority: 10 });
-```
-
-In this case, the second run will be executed first, because it's priority moved it 1 second ahead of the first run.
-
-
- We purposefully chose to use a time duration as the priority value instead of specifying priority
- levels, because priority levels can cause "level starvation" where lower priority runs are never
- executed because there are always higher priority runs in the queue.
-
-
-### Global lifecycle hooks
-
-We've added a new way to register global lifecycle hooks that are executed for all runs, regardless of the task. Previously, this was only possible in the `trigger.config.ts` file, but now you can register them anywhere in your codebase:
-
-```ts
-import { tasks } from "@trigger.dev/sdk";
-
-tasks.onStart(({ ctx, payload, task }) => {
- console.log("Run started", ctx.run);
-});
-
-tasks.onSuccess(({ ctx, output }) => {
- console.log("Run finished", ctx.run);
-});
-
-tasks.onFailure(({ ctx, error }) => {
- console.log("Run failed", ctx.run);
-});
-```
-
-### `init.ts`
-
-If you create a `init.ts` file at the root of your trigger directory, it will be automatically loaded when a task is executed. This is useful if you want to register global lifecycle hooks, or initialize a database connection, etc.
-
-```ts init.ts
-import { tasks } from "@trigger.dev/sdk";
-
-tasks.onStart(({ ctx, payload, task }) => {
- console.log("Run started", ctx.run);
-});
-```
-
-### onWait and onResume
-
-We've added two new lifecycle hooks that allow you to run code when a run is paused or resumed because of a wait:
-
-```ts
-export const myTask = task({
- id: "my-task",
- onWait: async ({ wait }) => {
- console.log("Run paused", wait);
- },
- onResume: async ({ wait }) => {
- console.log("Run resumed", wait);
- },
- run: async (payload: any, { ctx }) => {
- console.log("Run started", ctx.run);
-
- await wait.for({ seconds: 10 });
-
- console.log("Run finished", ctx.run);
- },
-});
-```
-
-### onComplete
-
-We've added a new lifecycle hook that is executed when a run completes, regardless of whether it succeeded or failed:
-
-```ts
-tasks.onComplete(({ ctx, result }) => {
- if (result.ok) {
- console.log("Run succeeded", result.data);
- } else {
- console.log("Run failed", result.error);
- }
-});
-```
-
-### onCancel
-
-Available in v4.0.0-beta.12 and later.
-
-You can now 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
-tasks.onCancel(({ ctx, signal }) => {
- console.log("Run cancelled", 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
-import { logger, tasks, schemaTask } from "@trigger.dev/sdk";
-import { streamText } from "ai";
-import { z } from "zod";
-
-export const interruptibleChat = schemaTask({
- id: "interruptible-chat",
- description: "Chat with the AI",
- schema: z.object({
- prompt: z.string().describe("The prompt to chat with the AI"),
- }),
- run: async ({ prompt }, { signal }) => {
- const chunks: TextStreamPart<{}>[] = [];
-
- // 👇 This is a global onCancel hook, but it's inside of the run function
- tasks.onCancel(async () => {
- // We have access to the chunks here, and can save them to the database
- await saveChunksToDatabase(chunks);
- });
-
- try {
- const result = streamText({
- model: getModel(),
- prompt,
- experimental_telemetry: {
- isEnabled: true,
- },
- tools: {},
- abortSignal: signal, // 👈 Pass the signal to the streamText function, which aborts with the run is cancelled
- onChunk: ({ chunk }) => {
- chunks.push(chunk);
- },
- });
-
- const textParts = [];
-
- for await (const part of result.textStream) {
- textParts.push(part);
- }
-
- return textParts.join("");
- } catch (error) {
- if (error instanceof Error && error.name === "AbortError") {
- // streamText will throw an AbortError if the signal is aborted, so we can handle it here
- } else {
- throw error;
- }
- }
- },
-});
-```
-
-The `onCancel` hook can optionally wait for the `run` function to finish, and access the output of the run:
-
-```ts
-import { logger, task } from "@trigger.dev/sdk";
-import { setTimeout } from "node:timers/promises";
-
-export const cancelExampleTask = task({
- id: "cancel-example",
- // Signal will be aborted when the task is cancelled 👇
- run: async (payload: { message: string }, { signal }) => {
- try {
- // We pass the signal to setTimeout to abort the timeout if the task is cancelled
- await setTimeout(10_000, undefined, { signal });
- } catch (error) {
- // Ignore the abort error
- }
-
- // Do some more work here
-
- return {
- message: "Hello, world!",
- };
- },
- onCancel: async ({ runPromise }) => {
- // You can await the runPromise to get the output of the task
- const output = await runPromise;
- },
-});
-```
-
-
- You will have up to 30 seconds to complete the `runPromise` in the `onCancel` hook. After that
- point the process will be killed.
-
-
-### Improved middleware and locals
-
-Our task middleware system is now much more useful. Previously it only ran "around" the `run` function, but now we've hoisted it to the top level and it now runs before/after all the other hooks.
-
-We've also added a new `locals` API that allows you to share data between middleware and hooks.
-
-```ts db.ts
-import { locals } from "@trigger.dev/sdk";
-import { logger, tasks } from "@trigger.dev/sdk";
-
-// This would be type of your database client here
-const DbLocal = locals.create<{ connect: () => Promise; disconnect: () => Promise }>(
- "db"
-);
-
-export function getDb() {
- return locals.getOrThrow(DbLocal);
-}
-
-export function setDb(db: { connect: () => Promise }) {
- locals.set(DbLocal, db);
-}
-
-tasks.middleware("db", async ({ ctx, payload, next, task }) => {
- // This would be your database client here
- const db = locals.set(DbLocal, {
- connect: async () => {
- logger.info("Connecting to the database");
- },
- disconnect: async () => {
- logger.info("Disconnecting from the database");
- },
- });
-
- await db.connect();
-
- await next();
-
- await db.disconnect();
-});
-
-// Disconnect when the run is paused
-tasks.onWait("db", async ({ ctx, payload, task }) => {
- const db = getDb();
- await db.disconnect();
-});
-
-// Reconnect when the run is resumed
-tasks.onResume("db", async ({ ctx, payload, task }) => {
- const db = getDb();
- await db.connect();
-});
-```
-
-Now in your tasks `run` function and all your hooks (global or task specific) you can access the database client using `getDb()`:
-
-```ts
-import { getDb } from "./db";
-
-export const myTask = task({
- run: async (payload: any, { ctx }) => {
- const db = getDb();
- await db.query("SELECT 1");
- },
-});
-```
-
-### Hidden tasks
-
-Previously, you were required to export the task from a file in your trigger directory to be able to execute it. We've changed the way tasks are indexed and this requirement has been removed. So you can now just define a task without exporting it, and everything will still work:
-
-```ts trigger/my-task.ts
-import { task } from "@trigger.dev/sdk";
-
-const myTask = task({
- run: async (payload: any, { ctx }) => {},
-});
-```
-
-You can use this to define "hidden" tasks that should only ever be triggered by other tasks in the same file:
-
-```ts trigger/my-task.ts
-import { task } from "@trigger.dev/sdk";
-
-const myTask = task({
- run: async (payload: any, { ctx }) => {},
-});
-
-export const myTask2 = task({
- run: async (payload: any, { ctx }) => {
- await myTask.trigger(payload);
- },
-});
-```
-
-Or you can create a package of reusable tasks that can be imported and used in your tasks, without having to re-export them:
-
-```ts trigger/my-task.ts
-import { task } from "@trigger.dev/sdk";
-import { sendToSlack } from "@repo/tasks";
-
-export const myTask = task({
- run: async (payload: any, { ctx }) => {
- await sendToSlack.trigger(payload);
- },
-});
-```
-
-### useWaitToken
-
-We've added a new `useWaitToken` react hook that allows you to complete a wait token from a React component, using a Public Access Token.
-
-```ts backend.ts
-import { wait } from "@trigger.dev/sdk";
-
-// Somewhere in your code, you'll need to create the token and then pass the token ID and the public token to the frontend
-const token = await wait.createToken({
- timeout: "10m",
-});
-
-return {
- tokenId: token.id,
- publicToken: token.publicAccessToken, // An automatically generated public access token that expires in 1 hour
-};
-```
-
-Now you can use the `useWaitToken` hook in your frontend code:
-
-```tsx frontend.tsx
-import { useWaitToken } from "@trigger.dev/react-hooks";
-
-export function MyComponent({ publicToken, tokenId }: { publicToken: string; tokenId: string }) {
- const { complete } = useWaitToken(tokenId, {
- accessToken: publicToken,
- });
-
- return ;
-}
-```
-
-### `ai.tool`
-
-We've added a new `ai.tool` function that allows you to create an AI tool from an existing `schemaTask` to use with the Vercel [AI SDK](https://vercel.com/docs/ai-sdk):
-
-```ts
-import { ai } from "@trigger.dev/sdk/ai";
-import { schemaTask } from "@trigger.dev/sdk";
-import { z } from "zod";
-import { generateText } from "ai";
-
-const myToolTask = schemaTask({
- id: "my-tool-task",
- schema: z.object({
- foo: z.string(),
- }),
- run: async (payload: any, { ctx }) => {},
-});
-
-const myTool = ai.tool(myToolTask);
-
-export const myAiTask = schemaTask({
- id: "my-ai-task",
- schema: z.object({
- text: z.string(),
- }),
- run: async (payload, { ctx }) => {
- const { text } = await generateText({
- prompt: payload.text,
- model: openai("gpt-4o"),
- tools: {
- myTool,
- },
- });
- },
-});
-```
-
-You can also pass the `experimental_toToolResultContent` option to the `ai.tool` function to customize the content of the tool result:
-
-```ts
-import { openai } from "@ai-sdk/openai";
-import { Sandbox } from "@e2b/code-interpreter";
-import { ai } from "@trigger.dev/sdk/ai";
-import { schemaTask } from "@trigger.dev/sdk/v3";
-import { generateObject } from "ai";
-import { z } from "zod";
-
-const chartTask = schemaTask({
- id: "chart",
- description: "Generate a chart using natural language",
- schema: z.object({
- input: z.string().describe("The chart to generate"),
- }),
- run: async ({ input }) => {
- const code = await generateObject({
- model: openai("gpt-4o"),
- schema: z.object({
- code: z.string().describe("The Python code to execute"),
- }),
- system: `
- You are a helpful assistant that can generate Python code to be executed in a sandbox, using matplotlib.pyplot.
-
- For example:
-
- import matplotlib.pyplot as plt
- plt.plot([1, 2, 3, 4])
- plt.ylabel('some numbers')
- plt.show()
-
- Make sure the code ends with plt.show()
- `,
- prompt: input,
- });
-
- const sandbox = await Sandbox.create();
-
- const execution = await sandbox.runCode(code.object.code);
-
- const firstResult = execution.results[0];
-
- if (firstResult.png) {
- return {
- chart: firstResult.png,
- };
- } else {
- throw new Error("No chart generated");
- }
- },
-});
-
-// This is useful if you want to return an image from the tool
-export const chartTool = ai.tool(chartTask, {
- experimental_toToolResultContent: (result) => {
- return [
- {
- type: "image",
- data: result.chart,
- mimeType: "image/png",
- },
- ];
- },
-});
-```
-
-You can also now get access to the current tool execution options inside the task run function using the `ai.currentToolOptions()` function:
-
-```ts
-import { ai } from "@trigger.dev/sdk/ai";
-import { schemaTask } from "@trigger.dev/sdk";
-import { z } from "zod";
-
-const myToolTask = schemaTask({
- id: "my-tool-task",
- schema: z.object({
- foo: z.string(),
- }),
- run: async (payload, { ctx }) => {
- const toolOptions = ai.currentToolOptions();
- console.log(toolOptions);
- },
-});
-
-export const myAiTask = ai.tool(myToolTask);
-```
-
-See the [AI SDK tool execution options docs](https://sdk.vercel.ai/docs/ai-sdk-core/tools-and-tool-calling#tool-execution-options) for more details on the tool execution options.
-
-
- `ai.tool` is compatible with `schemaTask`'s defined with Zod and ArkType schemas, or any schemas
- that implement a `.toJsonSchema()` function.
-
-
-## How to migrate to v4
-
-First read the deprecations, breaking changes, and known issues sections below.
-
-We recommend the following steps to migrate to v4:
-
-1. Install the v4 package.
-2. Run the `trigger dev` CLI command and test your tasks locally, fixing any breaking changes.
-3. Deploy to the staging environment and test your tasks in staging, fixing any breaking changes. (this step is optional, but highly recommended)
-4. Once you've verified that v4 is working as expected, you should deploy your application backend with the updated v4 package.
-5. Once you've deployed your application backend, you should deploy your tasks to the production environment.
-
-Note that between steps 4 and 5, runs triggered with the v4 package will continue using v3, and only new runs triggered after step 5 is complete will use v4.
-
-
- Once v4 is activated in your environment, there will be a period of time where old runs will
- continue to execute using v3, while new runs will use v4. Because these engines use completely
- different underlying queues and concurrency models, it's possible you may have up to double the
- amount of concurrently executing runs. Once the runs drain from the old run engine, the
- concurrency will return to normal.
-
-
-## Installation
-
-To opt-in to using v4, you will need to update your dependencies to the latest version of the `v4-beta` tag.
-
-
-
-```bash npm
-npm add @trigger.dev/sdk@v4-beta -E
-```
-
-```bash yarn
-yarn add @trigger.dev/sdk@v4-beta -E
-```
-
-```bash pnpm
-pnpm add @trigger.dev/sdk@v4-beta -E
-```
-
-
-
- You will need to do this for all your `@trigger.dev/*` packages.
-
-You'll also need to use the `v4-beta` version of the `trigger.dev` CLI package:
-
-
-
-```bash npx
-npx trigger.dev@v4-beta dev
-```
-
-```bash yarn
-yarn dlx trigger.dev@v4-beta dev
-```
-
-```bash pnpm
-pnpm dlx trigger.dev@v4-beta dev
-```
-
-
-
-## Known issues
-
-During the beta we will be tracking issues and releasing regular fixes.
-
-## Deprecations
-
-We've deprecated the following APIs:
-
-### @trigger.dev/sdk/v3
-
-We've deprecated the `@trigger.dev/sdk/v3` import path and moved to a new path:
-
-```ts
-// This still works, but will be removed in a future version
-import { task } from "@trigger.dev/sdk/v3";
-
-// This is the new path
-import { task } from "@trigger.dev/sdk";
-```
-
-### `handleError` and `init`
-
-We've renamed the `handleError` hook to `catchError` to better reflect that it can catch and react to errors. `handleError` will be removed in a future version.
-
-`init` was previously used to initialize data used in the run function:
-
-```ts
-import { task } from "@trigger.dev/sdk";
-
-const myTask = task({
- init: async () => {
- return {
- myClient: new MyClient(),
- };
- },
- run: async (payload: any, { ctx, init }) => {
- const client = init.myClient;
- await client.doSomething();
- },
-});
-```
-
-This has now been deprecated in favor of the `locals` API and middleware. See the [Improved middleware and locals](#improved-middleware-and-locals) section for more details.
-
-### toolTask
-
-We've deprecated the `toolTask` function, which created both a Trigger.dev task and a tool compatible with the Vercel [AI SDK](https://vercel.com/docs/ai-sdk):
-
-```ts
-import { toolTask, schemaTask } from "@trigger.dev/sdk";
-import { z } from "zod";
-import { generateText } from "ai";
-
-const myToolTask = toolTask({
- id: "my-tool-task",
- run: async (payload: any, { ctx }) => {},
-});
-
-export const myAiTask = schemaTask({
- id: "my-ai-task",
- schema: z.object({
- text: z.string(),
- }),
- run: async (payload, { ctx }) => {
- const { text } = await generateText({
- prompt: payload.text,
- model: openai("gpt-4o"),
- tools: {
- myToolTask,
- },
- });
- },
-});
-```
-
-We've replaced the `toolTask` function with the `ai.tool` function, which creates an AI tool from an existing `schemaTask`. See the [ai.tool](#ai-tool) section for more details.
-
-## Breaking changes
-
-### Queue changes
-
-Previously, it was possible to specify a queue name of a queue that did not exist, along with a concurrency limit. The queue would then be created "on-demand" with the specified concurrency limit. If the queue did exist, the concurrency limit of the queue would be updated to the specified value:
-
-```ts
-await myTask.trigger({ foo: "bar" }, { queue: { name: "my-queue", concurrencyLimit: 10 } });
-```
-
-This is no longer possible, and queues must now be defined ahead of time using the `queue` function:
-
-```ts
-import { queue } from "@trigger.dev/sdk";
-
-const myQueue = queue({
- name: "my-queue",
- concurrencyLimit: 10,
-});
-```
-
-Now when you trigger a task, you can only specify the queue by name:
-
-```ts
-await myTask.trigger({ foo: "bar" }, { queue: "my-queue" });
-```
-
-Or you can set the queue on the task:
-
-```ts
-import { queue, task } from "@trigger.dev/sdk";
-
-const myQueue = queue({
- name: "my-queue",
- concurrencyLimit: 10,
-});
-
-export const myTask = task({
- id: "my-task",
- queue: myQueue,
- run: async (payload: any, { ctx }) => {},
-});
-
-// You can optionally specify the queue directly on the task
-export const myTask2 = task({
- id: "my-task-2",
- queue: {
- name: "my-queue-2",
- concurrencyLimit: 50,
- },
- run: async (payload: any, { ctx }) => {},
-});
-```
-
-Now you can trigger these tasks without having to specify the queue name in the trigger options:
-
-```ts
-await myTask.trigger({ foo: "bar" }); // Will use the queue defined on the task
-await myTask2.trigger({ foo: "bar" }); // Will use the queue defined on the task
-```
-
-### Releasing concurrency on waits
-
-We've changed the default behavior on how concurrency is released when a run is paused or resumed because of a wait. Previously, the concurrency would be released immediately when the run was first paused, no matter the settings on the queue.
-
-Now we will no longer release concurrency on a queue that has a specified `concurrencyLimit` when a run is paused. You can go back to the previous behavior by setting the `releaseConcurrencyOnWaitpoint` option to `true` on the queue:
-
-```ts
-const myQueue = queue({
- name: "my-queue",
- concurrencyLimit: 10,
- releaseConcurrencyOnWaitpoint: true,
-});
-```
-
-You can also now control whether concurrency is released when performing a wait:
-
-```ts
-// This will prevent the run from being released back into the queue when the wait starts
-await wait.for({ seconds: 10, releaseConcurrency: false });
-```
-
-The new default behavior allows you to ensure that you can control the number of executing & waiting runs on a queue, and guarantee runs will resume once they are meant to be resumed.
-
-
- If you do choose to release concurrency on waits, be aware that it's possible a resume is delayed
- if the concurrency that was released is not available at the time the wait completes. In this
- case, the run will go back into the queue and will resume once concurrency becomes available.
-
-
-This new behavior effects all the wait functions:
-
-- Wait for duration (e.g. `wait.for({ seconds: 10 })`)
-- Wait for a child task to complete (e.g. `myTask.triggerAndWait()`, `myTask.batchTriggerAndWait([...])`)
-- Wait for a token to complete (e.g. `wait.forToken(tokenId)`)
-
-### Lifecycle hooks
-
-We've changed the function signatures of the lifecycle hooks to be more consistent and easier to use, by unifying all the parameters into a single object that can be destructured.
-
-Previously, hooks received a payload as the first argument and then an additional object as the second argument:
-
-```ts
-import { task } from "@trigger.dev/sdk";
-
-export const myTask = task({
- id: "my-task",
- onStart: (payload, { ctx }) => {},
- run: async (payload, { ctx }) => {},
-});
-```
-
-Now, all the parameters are passed in a single object:
-
-```ts
-import { task } from "@trigger.dev/sdk";
-
-export const myTask = task({
- id: "my-task",
- onStart: ({ payload, ctx }) => {},
- // The run function still uses separate parameters
- run: async (payload, { ctx }) => {},
-});
-```
-
-This is true for all the lifecycle hooks:
-
-```ts
-import { task } from "@trigger.dev/sdk";
-
-export const myTask = task({
- id: "my-task",
- onStart: ({ payload, ctx, task }) => {},
- onSuccess: ({ payload, ctx, task, output }) => {},
- onFailure: ({ payload, ctx, task, error }) => {},
- onWait: ({ payload, ctx, task, wait }) => {},
- onResume: ({ payload, ctx, task, wait }) => {},
- onComplete: ({ payload, ctx, task, result }) => {},
- catchError: ({ payload, ctx, task, error, retry, retryAt, retryDelayInMs }) => {},
- run: async (payload, { ctx }) => {},
-});
-```
-
-### Context changes
-
-We've made a few small changes to the `ctx` object:
-
-- `ctx.attempt.id` and `ctx.attempt.status` have been removed. `ctx.attempt.number` is still available.
-- `ctx.task.exportName` has been removed (since we no longer require tasks to be exported to be triggered).
-
-### BatchTrigger changes
-
-The `batchTrigger` function no longer returns a `runs` list directly. In v3, you could access the runs directly from the batch handle:
-
-```ts
-// In v3
-const batchHandle = await tasks.batchTrigger([
- [myTask, { foo: "bar" }],
- [myOtherTask, { baz: "qux" }],
-]);
-
-// You could access runs directly
-console.log(batchHandle.runs);
-```
-
-In v4, you now need to use the `runs.list()` method to get the list of runs:
-
-```ts
-// In v4
-const batchHandle = await tasks.batchTrigger([
- [myTask, { foo: "bar" }],
- [myOtherTask, { baz: "qux" }],
-]);
-
-// Now you need to call runs.list()
-const runs = await batchHandle.runs.list();
-console.log(runs);
-```
-
-## v4 beta Changelog
-
-
- [Trigger.dev v4
- release](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.0).
- Please see our upgrade to v4 docs to view the full changelog. Run Engine 2.0 (alpha)
- ([#1575](https://github.com/triggerdotdev/trigger.dev/pull/1575)), improved warm start times by
- eagerly creating the child TaskRunProcess when a previous run as completed
- ([#1879](https://github.com/triggerdotdev/trigger.dev/pull/1879)), and new lifecycle hooks
- ([#1817](https://github.com/triggerdotdev/trigger.dev/pull/1817)).
-
-
-
- [Release
- v4.0.0-beta.1](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.1).
- Fixed init.ts in custom trigger dirs and init command now correctly installs v4-beta packages
- ([#1914](https://github.com/triggerdotdev/trigger.dev/pull/1914)). Updated nypm package to support
- test-based bun.lock files and handle flush errors gracefully in dev
- ([#1914](https://github.com/triggerdotdev/trigger.dev/pull/1914)).
-
-
-
- [Release
- v4.0.0-beta.2](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.2).
- Managed run controller performance and reliability improvements
- ([#1927](https://github.com/triggerdotdev/trigger.dev/pull/1927)).
-
-
-
- [Release
- v4.0.0-beta.3](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.3).
- Improved usage flushing ([#1931](https://github.com/triggerdotdev/trigger.dev/pull/1931)) and
- fixed stalled run detection ([#1934](https://github.com/triggerdotdev/trigger.dev/pull/1934)).
-
-
-
- [Release
- v4.0.0-beta.5](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.5).
- Updated dependencies with various bug fixes and improvements.
-
-
-
- [Release
- v4.0.0-beta.6](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.6).
- The dev command now uses the platform-provided engine URL
- ([#1949](https://github.com/triggerdotdev/trigger.dev/pull/1949)).
-
-
-
- [Release
- v4.0.0-beta.7](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.7).
- Fixed runLimiter check on dequeueRuns
- ([#1953](https://github.com/triggerdotdev/trigger.dev/pull/1953)) and QUEUED status snapshot
- handler ([#1963](https://github.com/triggerdotdev/trigger.dev/pull/1963)).
-
-
-
- [Release
- v4.0.0-beta.8](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.8).
- Prevented large outputs from overwriting each other
- ([#1971](https://github.com/triggerdotdev/trigger.dev/pull/1971)).
-
-
-
- [Release
- v4.0.0-beta.9](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.9).
- Fixed default machine config indexing
- ([#1979](https://github.com/triggerdotdev/trigger.dev/pull/1979)).
-
-
-
- [Release
- v4.0.0-beta.10](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.10).
- TriggerApiError 4xx errors no longer cause tasks to be retried
- ([#1970](https://github.com/triggerdotdev/trigger.dev/pull/1970)). Fixed polling interval reset
- bug that could create duplicate intervals, protected against unexpected attempt number changes,
- and prevented run execution zombies after warm starts
- ([#1987](https://github.com/triggerdotdev/trigger.dev/pull/1987)).
-
-
-
- [Release
- v4.0.0-beta.11](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.11).
- Updated dependencies with various bug fixes and improvements.
-
-
-
- [Release
- v4.0.0-beta.12](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.12).
- Display clickable links in Cursor terminal
- ([#1998](https://github.com/triggerdotdev/trigger.dev/pull/1998)) and added AI assistance link
- when you have build errors ([#1925](https://github.com/triggerdotdev/trigger.dev/pull/1925)).
- Added validation when passing a directory to deploy command with helpful hints
- ([#2013](https://github.com/triggerdotdev/trigger.dev/pull/2013)).
-
-
-
- [Release
- v4.0.0-beta.13](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.13).
- Correctly resolved waitpoints that come in early, ensured correct state before requesting
- suspension, and fixed race conditions in snapshot processing
- ([#2006](https://github.com/triggerdotdev/trigger.dev/pull/2006)). Always print full deploy logs
- in CI ([#2006](https://github.com/triggerdotdev/trigger.dev/pull/2006)).
-
-
-
- [Release
- v4.0.0-beta.14](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.14).
- Updated dependencies with various bug fixes and improvements.
-
-
-
- [Release
- v4.0.0-beta.15](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.15).
- Added external log exporters and fixed missing external trace exporters in deployed tasks
- ([#2038](https://github.com/triggerdotdev/trigger.dev/pull/2038)). Log images sizes for
- self-hosted deploys ([#1764](https://github.com/triggerdotdev/trigger.dev/pull/1764)) and fixed
- init.ts auto-import for deployed workers
- ([#2041](https://github.com/triggerdotdev/trigger.dev/pull/2041)).
-
-
-
- [Release
- v4.0.0-beta.16](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.16).
- Fixed init.ts detection when using the sentry esbuild plugin
- ([#2051](https://github.com/triggerdotdev/trigger.dev/pull/2051)).
-
-
-
- [Release
- v4.0.0-beta.17](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.17).
- Exposed esbuild `keepNames` ([#2091](https://github.com/triggerdotdev/trigger.dev/pull/2091)) and
- `minify` options (experimental) ([#2091](https://github.com/triggerdotdev/trigger.dev/pull/2091)).
- Added `experimental_autoDetectExternal` trigger config option
- ([#2083](https://github.com/triggerdotdev/trigger.dev/pull/2083)) and output esbuild metafile,
- which can be inspected after `deploy --dry run`
- ([#2087](https://github.com/triggerdotdev/trigger.dev/pull/2087)).
-
-
-
- [Release
- v4.0.0-beta.18](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.18).
- Fixed dev runs ([#2094](https://github.com/triggerdotdev/trigger.dev/pull/2094)).
-
-
-
- [Release
- v4.0.0-beta.19](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.19).
- Added import timings and bundle size analysis - the dev command now warns about slow imports
- ([#2114](https://github.com/triggerdotdev/trigger.dev/pull/2114)). Fixed metadata collapsing
- correctness ([#2115](https://github.com/triggerdotdev/trigger.dev/pull/2115)), added support for
- Preview branches in v4 projects ([#2086](https://github.com/triggerdotdev/trigger.dev/pull/2086)),
- can now set project ref using the TRIGGER_PROJECT_REF env var
- ([#2109](https://github.com/triggerdotdev/trigger.dev/pull/2109)), and fixed `syncEnvVars` for
- non-preview deployments ([#2131](https://github.com/triggerdotdev/trigger.dev/pull/2131)).
-
-
-
- [Release
- v4.0.0-beta.20](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.20).
- Updated dependencies with various bug fixes and improvements.
-
-
-
- [Release
- v4.0.0-beta.21](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.21).
- Runtime agnostic SDK config via env vars
- ([#2132](https://github.com/triggerdotdev/trigger.dev/pull/2132)) and fixed update command version
- range handling ([#2153](https://github.com/triggerdotdev/trigger.dev/pull/2153)). Resolved issue
- where CLI could get stuck during deploy finalization, unified local and remote build logic with
- multi-platform build support, improved switch command which now accepts profile name as an
- argument, registry configuration is now fully managed by the webapp, the deploy `--self-hosted`
- flag is no longer required, and enhanced deployment error reporting and image digest retrieval
- ([#2138](https://github.com/triggerdotdev/trigger.dev/pull/2138)). Updated profile switcher
- ([#2150](https://github.com/triggerdotdev/trigger.dev/pull/2150)).
-
-
-
- [Release
- v4.0.0-beta.22](https://github.com/triggerdotdev/trigger.dev/releases/tag/trigger.dev%404.0.0-v4-beta.22).
- Fix update command version mismatch detection
- ([#2199](https://github.com/triggerdotdev/trigger.dev/pull/2199)). Add project details to the
- whoami command ([#2231](https://github.com/triggerdotdev/trigger.dev/pull/2231)). Serialize
- metadata to prevent invalid metadata from breaking run completions
- ([#2219](https://github.com/triggerdotdev/trigger.dev/pull/2219))
-
-This release also includes a new experimental `processKeepAlive` option, which allows you to
-keep the process alive after the run has completed for the next warm start, which makes warm starts even faster.
-
-Currently during a warm start, we still recreate the actual task run process between runs, leading to a completely fresh global environment for each run. This experimental option will keep the task run process alive between run executions, leading to even faster warm starts. This option is respected in both the `dev` CLI and in deployed tasks.
-
-To enable this option, add this to your `trigger.config.ts`:
-
-```ts
-import { defineConfig } from "@trigger.dev/sdk";
-
-export default defineConfig({
- project: "",
- // This is false by default
- experimental_processKeepAlive: true,
- maxDuration: 60,
-});
-```
-
-You can also pass an object to `experimental_processKeepAlive` to provide more options:
-
-```ts
-import { defineConfig } from "@trigger.dev/sdk";
-
-export default defineConfig({
- project: "",
- experimental_processKeepAlive: {
- enabled: true,
- // After 20 runs execute with a single process, we'll restart the process and start fresh
- maxExecutionsPerProcess: 20,
- // In dev, you can combine this option with setting a max pool size, giving you the ability to limit the number of processes created on your local dev machine. Has no effect on deployed tasks
- devMaxPoolSize: 10,
- },
- maxDuration: 60,
-});
-```
-
-## Gotchas
-
-- Be careful with memory usage and memory leaks, as this will cause memory to persist across run executions.
-- It's possible different tasks get executed in the same persisted process.
-- If you configure any 3rd party SDKs globally using env vars for API keys, those SDKs will not change between runs. So if you change an env var between runs, the SDK will be "stale" and continue using the old env var value. Instead, you should initialize SDKs using env vars at runtime (in any of the lifecycle hooks or inside the `run` function of a task.
-- Cancelling a task will cause the task run process to be restarted. Exiting the process is the only reliable way to actually stop a running function from stopping.
-- This DOES NOT effect cold starts, warm starts only will be improved.
-
-We recommend enabling this option and testing in a staging or preview environment before trying it out in prod, as there could be unknown issues depending on what you are doing in your tasks. [#2183](https://github.com/triggerdotdev/trigger.dev/pull/2183)
-
-
diff --git a/docs/upgrading-beta.mdx b/docs/upgrading-beta.mdx
index e5618f1cb5..532526fc4d 100644
--- a/docs/upgrading-beta.mdx
+++ b/docs/upgrading-beta.mdx
@@ -52,10 +52,10 @@ The new build system does not effect your trigger task files at all, so those ca
### `defineConfig`
-You should now import the `defineConfig` function from `@trigger.dev/sdk/v3` and export the config as the default export:
+You should now import the `defineConfig` function from `@trigger.dev/sdk` and export the config as the default export:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -71,7 +71,7 @@ The new build system will bundle all dependencies by default, so `dependenciesTo
Now that all dependencies are bundled, there are some situations where bundling a dependency doesn't work, and needs to be made external (e.g. when a dependency includes a native module). You can now specify these dependencies as build externals in the `defineConfig` function:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "",
@@ -96,7 +96,7 @@ npm add @trigger.dev/build@latest -D
Now you can import the `additionalFiles` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { additionalFiles } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -122,7 +122,7 @@ npm add @trigger.dev/build@latest -D
Now you can import the `additionalPackages` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { additionalPackages } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -146,7 +146,7 @@ npm add @trigger.dev/build@latest -D
Now you can import the `syncEnvVars` build extension and use it in your `trigger.config.ts` file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { syncEnvVars } from "@trigger.dev/build/extensions/core";
export default defineConfig({
@@ -174,7 +174,7 @@ See the [syncEnvVars](/deploy-environment-variables#sync-env-vars-from-another-s
If you make use of decorators in your code, and have enabled the `emitDecoratorMetadata` tsconfig compiler option, you'll need to enable this in the new build sytem using the `emitDecoratorMetadata` build extension:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { emitDecoratorMetadata } from "@trigger.dev/build/extensions/typescript";
export default defineConfig({
@@ -196,7 +196,7 @@ npm add @trigger.dev/build@latest -D
Then you can import the `prismaExtension` build extension and use it in your `trigger.config.ts` file, passing in the path to your Prisma schema file:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -221,7 +221,7 @@ This will make sure that your prisma client is generated during the build proces
If you want to also run migrations during the build process, you can pass in the `migrate` option:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -263,7 +263,7 @@ generator kysely {
```
```ts trigger.config.ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
export default defineConfig({
@@ -286,7 +286,7 @@ export default defineConfig({
Previously, we installed [Audio Waveform](https://github.com/bbc/audiowaveform) in the build image. That's been moved to a build extension:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { audioWaveform } from "@trigger.dev/build/extensions/audioWaveform";
export default defineConfig({
@@ -302,7 +302,7 @@ export default defineConfig({
You can now add esbuild plugins to customize the build process using the `esbuildPlugin` build extension. The example below shows how to automatically upload sourcemaps to Sentry using their esbuild plugin:
```ts
-import { defineConfig } from "@trigger.dev/sdk/v3";
+import { defineConfig } from "@trigger.dev/sdk";
import { esbuildPlugin } from "@trigger.dev/build/extensions";
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";
diff --git a/docs/wait-for-token.mdx b/docs/wait-for-token.mdx
index 8098243dfd..3091c4c5a6 100644
--- a/docs/wait-for-token.mdx
+++ b/docs/wait-for-token.mdx
@@ -1,17 +1,12 @@
---
title: "Wait for token"
description: "Wait until a token is completed."
-tag: "v4"
---
-import UpgradeToV4Note from "/snippets/upgrade-to-v4-note.mdx";
-
Waitpoint tokens pause task runs until you complete the token. They're commonly used for approval workflows and other scenarios where you need to wait for external confirmation, such as human-in-the-loop processes.
You can complete a token using the SDK or by making a POST request to the token's URL.
-
-
## Usage
To get started using wait tokens, you need to first create a token using the `wait.createToken` function:
@@ -496,3 +491,15 @@ const token = await wait.retrieveToken(tokenId);
console.log(token);
```
+
+## Wait idempotency
+
+You can pass an idempotency key to any wait function, allowing you to skip waits if the same idempotency key is used again. This can be useful if you want to skip waits when retrying a task, for example:
+
+```ts
+// Specify the idempotency key and TTL when creating a wait token
+const token = await wait.createToken({
+ idempotencyKey: "my-idempotency-key",
+ idempotencyKeyTTL: "1h",
+});
+```
\ No newline at end of file
diff --git a/docs/wait-for.mdx b/docs/wait-for.mdx
index f8c1ea10c8..ab212f573e 100644
--- a/docs/wait-for.mdx
+++ b/docs/wait-for.mdx
@@ -31,3 +31,12 @@ export const veryLongTask = task({
This allows you to write linear code without having to worry about the complexity of scheduling or managing cron jobs.
+
+## Wait idempotency
+
+You can pass an idempotency key to any wait function, allowing you to skip waits if the same idempotency key is used again. This can be useful if you want to skip waits when retrying a task, for example:
+
+```ts
+// Specify the idempotency key and TTL when waiting for a duration:
+await wait.for({ seconds: 10 }, { idempotencyKey: "my-idempotency-key", idempotencyKeyTTL: "1h" });
+```
\ No newline at end of file
diff --git a/docs/wait-until.mdx b/docs/wait-until.mdx
index adfb983b8a..0fb641ec2e 100644
--- a/docs/wait-until.mdx
+++ b/docs/wait-until.mdx
@@ -38,3 +38,16 @@ await wait.until({ date: new Date(date), throwIfInThePast: true });
```
You can of course use try/catch if you want to do something special in this case.
+
+## Wait idempotency
+
+You can pass an idempotency key to any wait function, allowing you to skip waits if the same idempotency key is used again. This can be useful if you want to skip waits when retrying a task, for example:
+
+```ts
+// Specify the idempotency key and TTL when waiting until a date:
+await wait.until({
+ date: futureDate,
+ idempotencyKey: "my-idempotency-key",
+ idempotencyKeyTTL: "1h",
+});
+```
\ No newline at end of file
diff --git a/docs/writing-tasks-introduction.mdx b/docs/writing-tasks-introduction.mdx
index c296140ef8..5f0bc33091 100644
--- a/docs/writing-tasks-introduction.mdx
+++ b/docs/writing-tasks-introduction.mdx
@@ -27,5 +27,7 @@ Before digging deeper into the details of writing tasks, you should read the [fu
| [Usage](/run-usage) | Get compute duration and cost from inside a run, or for a specific block of code. |
| [Context](/context) | Access the context of the task run. |
| [Bulk actions](/bulk-actions) | Run actions on many task runs at once. |
+| [Priority](/runs/priority) | Specify a priority when triggering a task. |
+| [Hidden tasks](/hidden-tasks) | Create tasks that are not exported from your trigger files but can still be executed. |