New mechanism for atomic deployments

Your app and your tasks deploy separately, so a fresh release can trigger tasks built from older code. Version skew protection pins every run to the deployment built from the same commit, across production, staging, and preview.

Oskar Otwinowski

Oskar Otwinowski

Software Engineer, Trigger.dev

--external-id $GIT_SHA

Every release opens a short gap: your app is already serving new code while the tasks it triggers are still deploying. Runs triggered in that gap no longer fall back to the previous version. Each one waits for the deployment built from its own commit, then runs there.

The id is the whole contract

Every deployment can carry an external id: the commit SHA it was built from, or any other value that identifies your build. Give your running app the same id and every task it triggers is pinned to the deployment built from that exact commit. Set it on deploy:


npx trigger.dev deploy --external-id "$(git rev-parse HEAD)"

then send the same value from your app when it triggers. A run waits at most an hour for its matching build; if that build never lands, the run expires. There's no mode to switch on: pin the two ids together and skew protection is on; leave them apart and runs behave exactly as they do today.

Automatic on Vercel, one variable elsewhere

Connect the Vercel integration and it wires this up for you. It sets the skew-protection variable on your project, tags each deployment with your commit SHA, and reads VERCEL_GIT_COMMIT_SHA back at runtime, so existing projects pick it up on their next deploy with nothing to configure. It covers production, staging, and preview alike, and never holds your Vercel deployment back waiting on a build.

The GitHub integration tags every deployment with its commit SHA for free. Give your app the same value through TRIGGER_EXTERNAL_DEPLOYMENT_ID and the pairing is complete.

Chat agents keep streaming through a redeploy

A chat.agent session pins to the deployment matching the app build that started it, so a live conversation keeps streaming straight through a redeploy instead of dropping. By default it follows that pin: once a new build lands, the agent hands the conversation to the matching deployment at the next turn boundary, with no client reconnect. To keep a session on the version it started on, set versionSkew: "hold" and drive the swap yourself with chat.requestUpgrade().

One variable to find the commit for you

Set TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION=1 in your app and you don't wire the id by hand. The SDK finds the commit SHA your host already injects at runtime: RAILWAY_GIT_COMMIT_SHA on Railway, RENDER_GIT_COMMIT on Render, and the equivalents on Cloudflare Pages, Koyeb, and most CI systems.

Pair it with the GitHub integration and neither end needs configuring. Your tasks deploy tagged with the commit they were built from, your app on Railway or Render resolves that same commit on its own, and every run lands on the matching deployment.

Retiring the deployment dance

Atomic deployments solved the same problem with more moving parts: gate your Vercel deploy on the task build, spin up a second Vercel deployment with TRIGGER_VERSION baked in, then promote it. Skew protection does it with one deployment, never blocks your app's deploy, and needs no setup.

The automatic atomic deployments setting in the Vercel integration is now deprecated. It keeps working and nothing switches off on you, but new connections have it off by default and skew protection is the supported path.

The manual atomic deploy workflow stays for when you specifically want your app held back until tasks finish building.

Try it

Deploy with --external-id, or connect the Vercel integration and get it for free. The full setup, per platform, is in the version skew protection guide.

Ready to start building?

Build and deploy your first task in 3 minutes.

Get started now