Skip to main content
Action required: Trigger.dev v3 deprecationWe’re retiring Trigger.dev v3. New v3 deploys will stop working from 1 April 2026. Trigger.dev v4 is stable, fully supported, and recommended for all users.Key dates:
  • 1 April 2026 — New v3 deploys will no longer work. Existing v3 runs will continue to execute.
  • 1 July 2026 — v3 will be fully shut down. All v3 runs will stop executing.
What you need to do: Migrate to v4 before April to avoid disruption to your task executions. The migration takes about 2 minutes — follow the steps on this page below. If you have questions or need help, contact us or reach out in our Discord.

What’s new in v4?

Node.js support

Trigger.dev runs your tasks on specific Node.js versions:

v3

  • Node.js 21.7.3

v4

  • Node.js 21.7.3 (default)
  • Node.js 22.16.0 (node-22)
  • Bun 1.3.3 (bun)
You can change the runtime by setting the runtime field in your trigger.config.ts file.

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.
When migrating from v3 to v4, our infrastructure IPs may change. If you use IP allowlisting (e.g. for databases or APIs), update your allowlists with the current static IPs before or immediately after switching to v4 to avoid connectivity issues or downtime.

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:
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:

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:
This has now been deprecated in favor of the locals API and middleware. See the 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:
We’ve replaced the toolTask function with the ai.tool function, which creates an AI tool from an existing schemaTask. See the 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:
This is no longer possible, and queues must now be defined ahead of time using the queue function:
Now when you trigger a task, you can only specify the queue by name:
Or you can set the queue on the task:
Now you can trigger these tasks without having to specify the queue name in the trigger options:
If you’re using concurrencyKey you can specify the queue and concurrencyKey like this:
For each unique value of concurrencyKey, a new queue will be created using the concurrencyLimit from the queue. This allows you to have a queue per user.

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:
Now, all the parameters are passed in a single object:
This is true for all the lifecycle hooks:

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:
In v4, you now need to use the batch.retrieve() method to get the batch with its runs:

OpenTelemetry

We are now using newer versions of the OpenTelemetry packages. This means that if you’re using custom exporters you may need to update the packages: