Skip to content

Commit ba90165

Browse files
committed
docs: task version skew protection, --external-id, and the atomic deployments deprecation
New deployment/version-skew-protection page: the skew problem, the --external-id primitive and its reuse behaviour, runtime discovery (call option, configure(), TRIGGER_EXTERNAL_DEPLOYMENT_ID, and the gated platform/CI/generic commit-SHA variables with the build-time caveat), the manual any-platform recipe, waiting/expiry semantics, precedence, and automatic skew protection on Vercel. Deprecation callouts on the atomic deployments page and the Vercel integration page; --external-id/--force added to the CLI deploy reference; redirect from deployment/vercel-skew-protection so existing webapp links resolve (TRI-13002).
1 parent 1034b61 commit ba90165

9 files changed

Lines changed: 562 additions & 14 deletions

docs/deployment/atomic-deployment.mdx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ sidebarTitle: "Atomic deploys"
44
description: "Use atomic deploys to coordinate changes to your tasks and your application."
55
---
66

7+
<Warning>
8+
**There's now a simpler way to do this.** [Version skew
9+
protection](/deployment/version-skew-protection) solves the same problem without a second
10+
deployment, without gating your app's deploy, and without setting `TRIGGER_VERSION` — and it covers
11+
staging and preview as well as production. If you use the [Vercel
12+
integration](/vercel-integration), its **automatic atomic deployments** setting is now deprecated
13+
in favour of skew protection.
14+
15+
The manual workflows on this page still work, and remain the right answer if you specifically want
16+
your application's deployment held back until your tasks have finished building.
17+
</Warning>
18+
719
Atomic deploys in Trigger.dev allow you to synchronize the deployment of your application with a specific version of your tasks. This ensures that your application always uses the correct version of its associated tasks, preventing inconsistencies or errors due to version mismatches.
820

921
## How it works

docs/deployment/overview.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ If you want to set a global version to run all tasks against, you can use the `T
122122
TRIGGER_VERSION=20250228.1
123123
```
124124

125+
<Tip>
126+
If what you actually want is for each release of your app to run against the tasks built from the
127+
same commit, you don't need to plumb version numbers around by hand. See [version skew
128+
protection](/deployment/version-skew-protection).
129+
</Tip>
130+
125131
### Child tasks and auto-version locking
126132

127133
Trigger and wait functions version lock child task runs to the parent task run version. This ensures the results from child runs match what the parent task is expecting. If you don't wait then version locking doesn't apply.
@@ -155,7 +161,7 @@ Or from the dashboard:
155161

156162
![Trigger.dev dashboard showing the promote button](/deployment/promote-button.png)
157163

158-
To learn more about skipping promotion and how this enables atomic deployments, see our [Atomic deployment](/deployment/atomic-deployment) guide.
164+
To learn more about skipping promotion and how this enables atomic deployments, see our [Atomic deployment](/deployment/atomic-deployment) guide. To keep your app and tasks in sync without coordinating promotion at all, see [version skew protection](/deployment/version-skew-protection).
159165

160166
## Staging deploys
161167

docs/deployment/version-skew-protection.mdx

Lines changed: 431 additions & 0 deletions
Large diffs are not rendered by default.

docs/docs.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@
187187
"github-actions",
188188
"deployment/preview-branches",
189189
"deployment/dev-branches",
190+
"deployment/version-skew-protection",
190191
"deployment/atomic-deployment",
191192
{
192193
"group": "Deployment integrations",
@@ -893,6 +894,11 @@
893894
{
894895
"source": "/guides/ai-chat",
895896
"destination": "/ai-chat/overview"
897+
},
898+
{
899+
"source": "/deployment/vercel-skew-protection",
900+
"destination": "/deployment/version-skew-protection",
901+
"permanent": true
896902
}
897903
]
898904
}

docs/github-actions.mdx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The instructions below are specific to GitHub Actions, but the same concepts can
1111

1212
## GitHub Actions example
1313

14-
This simple GitHub action workflow will deploy your Trigger.dev tasks when new code is pushed to the `main` branch and the `trigger` directory has changes in it.
14+
This simple GitHub action workflow will deploy your Trigger.dev tasks when new code is pushed to the `main` branch.
1515

1616
<Warning>
1717
The deploy step will fail if any version mismatches are detected. Please see the [version
@@ -47,7 +47,7 @@ jobs:
4747
env:
4848
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
4949
run: |
50-
npx trigger.dev@latest deploy
50+
npx trigger.dev@latest deploy --external-id ${{ github.sha }}
5151
```
5252
5353
```yaml .github/workflows/release-trigger-staging.yml
@@ -76,13 +76,37 @@ jobs:
7676
env:
7777
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
7878
run: |
79-
npx trigger.dev@latest deploy --env staging
79+
npx trigger.dev@latest deploy --env staging --external-id ${{ github.sha }}
8080
```
8181
8282
</CodeGroup>
8383
8484
If you already have a GitHub action file, you can just add the final step "🚀 Deploy Trigger.dev" to your existing file.
8585
86+
### Pinning runs to the deployment you just built
87+
88+
The `--external-id ${{ github.sha }}` above tags the deployment with the commit it was built from. That is the first half of [version skew protection](/deployment/version-skew-protection): to complete it, give your running application the **same value** so it sends that id when it triggers.
89+
90+
```bash
91+
# In your application's runtime environment, for the release built from this commit
92+
TRIGGER_EXTERNAL_DEPLOYMENT_ID=<the-same-commit-sha>
93+
```
94+
95+
Every task triggered by that release is then pinned to the deployment built from the same commit — and runs triggered before the task build finishes wait for it rather than executing on the previous version.
96+
97+
<Note>
98+
Tagging the deployment is harmless on its own: if nothing sends a matching id, runs behave exactly
99+
as they do today. `--external-id` also makes repeat deploys idempotent — re-running the workflow
100+
for a commit that is already deployed reports the existing version instead of building again.
101+
102+
Two things follow from that. Because no build runs, a re-run after changing a synced environment
103+
variable won't pick the new value up — make an empty commit, or pass `--force`. And if you add a
104+
`paths:` filter to this workflow, `${{ github.sha }}` stops being a safe id: commits that don't
105+
touch your tasks never produce a deployment carrying that SHA, so every run from those releases
106+
expires. See [when nothing ever
107+
lands](/deployment/version-skew-protection#when-nothing-ever-lands).
108+
</Note>
109+
86110
## Preview branches
87111

88112
To deploy to preview branches from Pull Requests and have them archived when PRs are merged or closed, use a workflow that runs on `pull_request` with **all four types** including `closed`:
@@ -109,7 +133,7 @@ jobs:
109133
run: npm install
110134
111135
- name: Deploy preview branch
112-
run: npx trigger.dev@latest deploy --env preview
136+
run: npx trigger.dev@latest deploy --env preview --external-id ${{ github.sha }}
113137
env:
114138
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
115139
```

docs/github-integration.mdx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,18 @@ The name of the preview branch matches the branch name of the pull request.
7272
Preview branch deployments require the preview environment to be enabled on your project. Learn more about [preview branches](/deployment/preview-branches).
7373
</Note>
7474

75+
## Version skew protection
76+
77+
Every deployment the GitHub integration creates is tagged with the commit SHA it was built from. That is the deploy half of [version skew protection](/deployment/version-skew-protection) — you get it for free.
78+
79+
To complete it, give your running application the same value. Unlike the Vercel integration, we have no access to wherever your app is hosted, so this half is yours to set:
80+
81+
```bash
82+
TRIGGER_EXTERNAL_DEPLOYMENT_ID=<the-commit-sha-this-release-was-built-from>
83+
```
84+
85+
If your host already exposes the commit SHA at runtime, set `TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION=1` instead and the SDK will find it — see the [platform table](/deployment/version-skew-protection#hosting-platforms).
86+
7587
## Disconnecting a repository
7688

7789
You can disconnect a repository at any time from your project git settings. This will stop automatic deployments triggered from GitHub.

docs/snippets/cli-commands-deploy.mdx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ npx trigger.dev@latest deploy [path]
7777
Turn off syncing environment variables with the Trigger.dev instance.
7878
</ParamField>
7979

80+
<ParamField body="External id" type="--external-id">
81+
Attach your own identifier to this deployment — a commit SHA, release tag or CI run id, up to 128
82+
characters. Your app can then send the same id when triggering, and runs are pinned to this
83+
deployment. See [version skew protection](/deployment/version-skew-protection).
84+
85+
Repeating an id that is already deployed doesn't build again: the CLI reports the existing version,
86+
sets the same outputs, and exits successfully. Repeating an id that has a build in flight is an
87+
error. An id whose build failed rebuilds normally.
88+
89+
The short-circuit is keyed on the id, not on the build inputs — so redeploying the same id after
90+
changing a synced environment variable produces no new build.
91+
</ParamField>
92+
93+
<ParamField body="Force" type="--force">
94+
Start a new build for an `--external-id` that already has one. Non-destructive with respect to
95+
deployments that already succeeded — both remain and the newer version wins. If a build for that
96+
id is still in flight, `--force` **cancels** it first, so one id never has two live builds. A
97+
cancelled build usually stops within seconds, but one running on another machine can keep going
98+
briefly before it notices. Requires `--external-id`.
99+
</ParamField>
100+
80101
<ParamField body="Local build" type="--local-build">
81102
Force building the deployment image locally using your local Docker. This is automatic when self-hosting.
82103
</ParamField>

docs/vercel-integration.mdx

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: "Automatically deploy your tasks whenever you deploy to Vercel."
55

66
## How it works
77

8-
The Vercel integration connects your Vercel project to your Trigger.dev project so that every Vercel deployment automatically triggers a Trigger.dev deployment. It also syncs environment variables from Vercel into Trigger.dev and supports atomic deployments to keep your app and tasks in sync.
8+
The Vercel integration connects your Vercel project to your Trigger.dev project so that every Vercel deployment automatically triggers a Trigger.dev deployment. It also syncs environment variables from Vercel into Trigger.dev, and sets up [version skew protection](/deployment/version-skew-protection) so your app and tasks stay in sync.
99

1010
This eliminates the need to manually run the `trigger.dev deploy` command or maintain custom CI/CD workflows for Vercel-based projects.
1111

@@ -42,8 +42,7 @@ You can connect Vercel from two entry points:
4242
</Step>
4343

4444
<Step title="Configure build options">
45-
Optionally adjust [build options](#build-options) for atomic deployments, env var pulling, and new
46-
env var discovery.
45+
Optionally adjust [build options](#build-options) for env var pulling and new env var discovery.
4746
</Step>
4847

4948
<Step title="Connect GitHub">
@@ -99,7 +98,7 @@ The integration syncs environment variables in both directions:
9998

10099
The following variables are excluded from the Vercel → Trigger.dev sync:
101100

102-
- `TRIGGER_SECRET_KEY`, `TRIGGER_VERSION`, `TRIGGER_PREVIEW_BRANCH` (managed by Trigger.dev)
101+
- `TRIGGER_SECRET_KEY`, `TRIGGER_API_URL`, `TRIGGER_VERSION`, `TRIGGER_PREVIEW_BRANCH`, `TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION` (managed by Trigger.dev)
103102
- Sensitive/secret-type variables (Vercel API limitation)
104103

105104
You can control sync behavior per-variable from your project's Vercel settings. Deselecting a variable prevents its value from being updated during future syncs.
@@ -120,8 +119,41 @@ You can control sync behavior per-variable from your project's Vercel settings.
120119

121120
If you use [Supabase Branching](https://supabase.com/docs/guides/deployment/branching) or [Neon Database Branching](https://neon.tech/docs/guides/branching-intro) for preview environments, disable syncing for database env vars on the Environment Variables page and use the [syncSupabaseEnvVars](/config/extensions/syncEnvVars#syncsupabaseenvvars) or [syncNeonEnvVars](/config/extensions/syncEnvVars#syncneonenvvars) build extensions instead. These extensions automatically resolve the correct branch-specific credentials at build time.
122121

122+
## Version skew protection
123+
124+
Your Vercel app and your tasks are deployed separately, so there is always a window where a new app can trigger tasks built from older code. [Version skew protection](/deployment/version-skew-protection) closes that window: each Trigger.dev deployment is tagged with your commit SHA, your app sends the same SHA when it triggers, and every run is pinned to the deployment built from the same commit. Runs triggered before the task build finishes wait for it rather than running on the previous version.
125+
126+
The integration sets this up for you:
127+
128+
- It sets `TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION=1` on your Vercel project when you connect it, and re-asserts it on every build — so existing projects pick it up on their next deployment.
129+
- It passes your commit SHA as the deployment's external id.
130+
- `VERCEL_GIT_COMMIT_SHA` is available at runtime on Vercel, so the SDK finds the matching id with no work from you.
131+
132+
There is nothing to enable, and it works in production, staging and preview alike. Nothing is gated: your Vercel deployment is never held back.
133+
134+
<Note>
135+
Version skew protection requires the `@trigger.dev/sdk` release that introduces external
136+
deployment ids. Check the [release
137+
notes](https://github.com/triggerdotdev/trigger.dev/releases) for the exact version, or just use
138+
the latest. On an older SDK no id is sent and your runs execute on the current version, with no
139+
warning.
140+
</Note>
141+
142+
To opt out, set `TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION` to `0` on your Vercel project. The integration only writes the variable when it is absent, so a value you set is never overwritten.
143+
123144
## Atomic deployments
124145

146+
<Warning>
147+
**Automatic atomic deployments are deprecated.** Use [version skew
148+
protection](/deployment/version-skew-protection) instead — it needs no second Vercel deployment,
149+
never gates your app's deploy, doesn't touch `Auto-assign Custom Production Domains`, and covers
150+
staging and preview as well as production.
151+
152+
Nothing is being switched off. The setting stays in your project's Vercel settings, keeps working,
153+
and remains the way to hold your Vercel deployment back until your tasks have built. New
154+
connections have it off by default.
155+
</Warning>
156+
125157
Atomic deployments ensure your Vercel app and Trigger.dev tasks are deployed in sync. When enabled, Trigger.dev gates your Vercel deployment until the task build completes, then triggers a Vercel redeployment with the correct `TRIGGER_VERSION` set. This guarantees your app always uses the matching version of your tasks.
126158

127159
```mermaid
@@ -152,15 +184,16 @@ sequenceDiagram
152184
TD->>TD: Promote build
153185
```
154186

155-
Atomic deployments are enabled for the production environment by default.
187+
Atomic deployments are off by default for new connections. Projects that already had them enabled keep them enabled until you turn them off. Enabling them asks you to confirm first.
156188

157189
<Note>
158190
When atomic deployments are enabled, the integration automatically disables `Auto-assign Custom
159191
Production Domains` on your Vercel project. This is required so that Vercel doesn't promote a
160-
deployment before the Trigger.dev build is ready.
192+
deployment before the Trigger.dev build is ready. If you turn atomic deployments off, re-enable
193+
that setting in Vercel or promote deployments yourself.
161194
</Note>
162195

163-
Previously, setting up atomic deployments with Vercel required custom GitHub Actions workflows. The Vercel integration automates this entirely. For more details on how atomic deployments work, see [Atomic deploys](/deployment/atomic-deployment).
196+
Previously, setting up atomic deployments with Vercel required custom GitHub Actions workflows. The Vercel integration automates this entirely. For more details on how atomic deployments work, see [Atomic deploys](/deployment/atomic-deployment). For how to move off them, see [replacing automatic atomic deployments](/deployment/version-skew-protection#replacing-automatic-atomic-deployments).
164197

165198
## Environment mapping
166199

@@ -184,7 +217,7 @@ If your Vercel project has a custom environment, you can select which one maps t
184217

185218
You can configure the following settings per-environment from your project's Vercel settings:
186219

187-
- **Atomic deployments**: Controls whether Trigger.dev and Vercel deployments are synchronized. Enabled for production by default.
220+
- **Atomic deployments** (deprecated): Controls whether Trigger.dev gates and redeploys your Vercel deployment to keep it in sync. Off by default for new connections — use [version skew protection](/deployment/version-skew-protection) instead.
188221
- **Pull env vars before build**: When enabled, Trigger.dev pulls the latest environment variables from Vercel before each build. Enabled for production, staging, and preview by default.
189222
- **Discover new env vars**: When enabled, new environment variables found in Vercel that don't yet exist in Trigger.dev are created automatically during builds. Only available for environments that also have env var pulling enabled. Enabled for production, staging, and preview by default.
190223

@@ -201,7 +234,8 @@ Disconnecting stops automatic deployments, environment variable syncing, and dep
201234

202235
## Related
203236

237+
- [Version skew protection](/deployment/version-skew-protection)
204238
- [GitHub integration](/github-integration)
205-
- [Atomic deploys](/deployment/atomic-deployment)
239+
- [Atomic deploys](/deployment/atomic-deployment) (deprecated for Vercel)
206240
- [Environment variables](/deploy-environment-variables)
207241
- [Preview branches](/deployment/preview-branches)

docs/versioning.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ So a task run will continue running on the version it was locked to. We do this
4747

4848
Every deployment creates a new version of all tasks for that environment.
4949

50+
Because your application and your tasks deploy separately, a release of your app can briefly trigger tasks that belong to a different version. [Version skew protection](/deployment/version-skew-protection) pins each run to the deployment built from the same commit.
51+
5052
## Retries and reattempts
5153

5254
When a task has an uncaught error it will [retry](/errors-retrying), assuming you have not set `maxAttempts` to 0. Retries are locked to the original version of the run.

0 commit comments

Comments
 (0)