Skip to content

feat(sdk): allow opting out of TRIGGER_VERSION locking via version: null#3413

Closed
jorgehermo9 wants to merge 1 commit intotriggerdotdev:mainfrom
jorgehermo9:feat/opt-out-trigger-version-locking
Closed

feat(sdk): allow opting out of TRIGGER_VERSION locking via version: null#3413
jorgehermo9 wants to merge 1 commit intotriggerdotdev:mainfrom
jorgehermo9:feat/opt-out-trigger-version-locking

Conversation

@jorgehermo9
Copy link
Copy Markdown

Closes #3380.

Summary

  • TriggerOptions.version is widened from string to string | null.
  • ApiClientConfiguration gains a version?: string | null field that applies inside auth.withAuth(...) scopes.
  • Passing null omits lockToVersion from the request so the server resolves to the current deployed version, ignoring the TRIGGER_VERSION env var.

Resolution precedence (highest first):

  1. Per-call options.version
  2. Scoped ApiClientConfiguration.version
  3. TRIGGER_VERSION env var

undefined at any level falls through to the next; only null explicitly unpins. The parent-run lockToVersion: taskContext.worker?.version paths (triggerAndWait / batchTriggerAndWait / child tasks) are unchanged.

Motivation

A single Node.js process (Next.js on Vercel) triggers tasks in two Trigger.dev projects. The Vercel integration injects TRIGGER_VERSION scoped to project A, but the SDK's tasks.trigger() unconditionally sends it as lockToVersion for calls targeting project B too. When project B's deploy drifts behind, every cross-project call fails with a "version not found" 500. There was no supported SDK-level opt-out.

Changes

File Change
packages/core/src/v3/apiClientManager/types.ts Add version?: string | null to ApiClientConfiguration
packages/core/src/v3/apiClientManager/index.ts Add resolveLockToVersion() method with three-level precedence
packages/core/src/v3/types/tasks.ts Widen TriggerOptions.version to string | null, update JSDoc
packages/trigger-sdk/src/v3/shared.ts 7 call sites use apiClientManager.resolveLockToVersion(...), unused getEnvVar import removed
packages/core/test/apiClientManager.test.ts 12 new unit tests covering all resolution paths
.changeset/opt-out-trigger-version-locking.md Minor bump for @trigger.dev/core and @trigger.dev/sdk

Usage

// Scoped: every trigger inside this scope uses the current deployed version
await auth.withAuth({ secretKey: PROJECT_B_KEY, version: null }, async () => {
  await tasks.trigger("some-task", payload);
});

// Per-call: only this call is unpinned
await tasks.trigger("some-task", payload, { version: null });

Test plan

  • 12 new unit tests in packages/core/test/apiClientManager.test.ts (all resolution paths: call > scope > env, null sentinel at each level, explicit undefined passthrough)
  • Existing SDK tests green (pnpm exec vitest run in trigger-sdk: 10/10 pass)
  • Full core test suite green (424/424 pass)
  • TypeScript clean (pnpm exec tsc --noEmit in trigger-sdk: exit 0)
  • Grep verification: 0 remaining getEnvVar("TRIGGER_VERSION") in shared.ts, 7 resolveLockToVersion call sites, 7 untouched taskContext.worker?.version lines

…null`

Closes triggerdotdev#3380.

`TriggerOptions.version` is extended from `string` to `string | null`, and
`ApiClientConfiguration` gains a new `version?: string | null` field that
applies to every trigger inside an `auth.withAuth(...)` scope. Passing
`null` omits `lockToVersion` from the request so the server resolves to
the current deployed version, ignoring the `TRIGGER_VERSION` env var.

Motivating use case: a single Node.js process triggers tasks in two
Trigger.dev projects (e.g. a main project connected to the Vercel
integration plus a sibling project for autonomous agents). The ambient
`TRIGGER_VERSION` is scoped to the main project, and the SDK previously
had no way to opt cross-project calls out of that pin.

Resolution precedence (highest first):
  1. per-call `options.version`
  2. scoped `ApiClientConfiguration.version`
  3. `TRIGGER_VERSION` env var

`undefined` at any level falls through; only `null` explicitly unpins.
All 7 trigger paths in `shared.ts` route through the new
`apiClientManager.resolveLockToVersion(...)` helper. The parent-run
`lockToVersion: taskContext.worker?.version` paths (triggerAndWait /
batchTriggerAndWait / child tasks) are unchanged by design.
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 19, 2026

🦋 Changeset detected

Latest commit: 18df18c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 29 packages
Name Type
@trigger.dev/core Minor
@trigger.dev/sdk Minor
@trigger.dev/build Minor
trigger.dev Minor
@trigger.dev/python Minor
@trigger.dev/redis-worker Minor
@trigger.dev/schema-to-json Minor
@internal/cache Patch
@internal/clickhouse Patch
@internal/llm-model-catalog Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/tsql Patch
@internal/zod-worker Patch
@internal/sdk-compat-tests Patch
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
references-realtime-hooks-test Patch
references-realtime-streams Patch
references-telemetry Patch
@trigger.dev/react-hooks Minor
@trigger.dev/rsc Minor
@trigger.dev/database Minor
@trigger.dev/otlp-importer Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

Hi @jorgehermo9, thanks for your interest in contributing!

This project requires that pull request authors are vouched, and you are not in the list of vouched users.

This PR will be closed automatically. See https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md for more details.

@github-actions github-actions bot closed this Apr 19, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 19, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fd95f702-be28-486b-8771-d1d27bdf7bcf

📥 Commits

Reviewing files that changed from the base of the PR and between 6e6deb4 and 18df18c.

📒 Files selected for processing (6)
  • .changeset/opt-out-trigger-version-locking.md
  • packages/core/src/v3/apiClientManager/index.ts
  • packages/core/src/v3/apiClientManager/types.ts
  • packages/core/src/v3/types/tasks.ts
  • packages/core/test/apiClientManager.test.ts
  • packages/trigger-sdk/src/v3/shared.ts

Walkthrough

This pull request introduces an opt-out mechanism for TRIGGER_VERSION locking in Trigger.dev. It extends TriggerOptions.version and introduces a new ApiClientConfiguration.version property to accept null in addition to version strings. When null is explicitly provided—either per-call or scoped—the request omits lockToVersion, allowing the server to resolve the currently deployed version and ignore the TRIGGER_VERSION environment variable. A new resolveLockToVersion() method implements version resolution with defined precedence: per-call TriggerOptions.version, then scoped ApiClientConfiguration.version, then TRIGGER_VERSION environment variable. The implementation includes comprehensive test coverage and updates multiple code paths across the SDK to use the new resolution method.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jorgehermo9 jorgehermo9 deleted the feat/opt-out-trigger-version-locking branch April 19, 2026 20:10
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment on lines 115 to 117
runWithConfig<R extends (...args: any[]) => Promise<any>>(
config: ApiClientConfiguration,
fn: R
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 runWithConfig uses global state, not AsyncLocalStorage — concurrent scopes can collide

The runWithConfig method at packages/core/src/v3/apiClientManager/index.ts:115-126 stores scoped config in a global variable via registerGlobal, not via AsyncLocalStorage. If two concurrent async operations both call runWithConfig (e.g., two simultaneous auth.withAuth blocks), the second call overwrites the global config, and the first call's finally block then restores the wrong original. This is a pre-existing design issue (not introduced by this PR), but the new version field is now also subject to this race. In practice, this is likely fine for server-side usage where each request runs in isolation, but it's worth noting for library consumers running multiple scoped operations concurrently in the same process.

(Refers to lines 115-126)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@jorgehermo9 jorgehermo9 restored the feat/opt-out-trigger-version-locking branch April 19, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Allow opting out of TRIGGER_VERSION locking on a per-call basis

1 participant