Skip to content

Object Storage seamless migration#3275

Draft
matt-aitken wants to merge 6 commits intomainfrom
object-storage-migration
Draft

Object Storage seamless migration#3275
matt-aitken wants to merge 6 commits intomainfrom
object-storage-migration

Conversation

@matt-aitken
Copy link
Member

This allows seamless migration to different object storage.

Existing runs that have offloaded payloads/outputs will continue to use the default object store (configured using OBJECT_STORE_* env vars).

You can add additional stores by setting new env vars:

  • OBJECT_STORE_DEFAULT_PROTOCOL this determines where new run large payloads will get stored.
  • If you set that you need to set new env vars for that protocol.

Example:

OBJECT_STORE_DEFAULT_PROTOCOL=“s3"
OBJECT_STORE_S3_BASE_URL=https://s3.us-east-1.amazonaws.com
OBJECT_STORE_S3_ACCESS_KEY_ID=<val>
OBJECT_STORE_S3_SECRET_ACCESS_KEY=<val>
OBJECT_STORE_S3_REGION=us-east-1
OBJECT_STORE_S3_SERVICE=s3

This allows seamless migration to different object storage.
@mintlify
Copy link
Contributor

mintlify bot commented Mar 26, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
trigger 🟢 Ready View Preview Mar 26, 2026, 10:40 AM

@changeset-bot
Copy link

changeset-bot bot commented Mar 26, 2026

⚠️ No Changeset found

Latest commit: feac4be

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1d90f929-258a-410b-8780-5d0102ef66ca

📥 Commits

Reviewing files that changed from the base of the PR and between c907914 and baa015c.

📒 Files selected for processing (3)
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: For apps and internal packages (apps/*, internal-packages/*), use pnpm run typecheck --filter <package> for verification, never use build as it proves almost nothing about correctness
Use testcontainers helpers (redisTest, postgresTest, containerTest from @internal/testcontainers) for integration tests with Redis and PostgreSQL instead of mocking
When writing Trigger.dev tasks, always import from @trigger.dev/sdk - never use @trigger.dev/sdk/v3 or deprecated client.defineJob

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

**/*.{ts,tsx,js,jsx}: Use pnpm for package management in this monorepo (version 10.23.0) with Turborepo for orchestration - run commands from root with pnpm run
Add crumbs as you write code for debug tracing using // @Crumbs comments or `// `#region` `@crumbs blocks - they stay on the branch throughout development and are stripped via agentcrumbs strip before merge

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
apps/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When modifying only server components (apps/webapp/, apps/supervisor/, etc.) with no package changes, add a .server-changes/ file instead of a changeset

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
apps/webapp/app/**/*.{ts,tsx,server.ts}

📄 CodeRabbit inference engine (apps/webapp/CLAUDE.md)

Access environment variables via env export from app/env.server.ts. Never use process.env directly

Files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
apps/webapp/app/v3/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Organize services in the webapp following the pattern app/v3/services/*/*.server.ts

Files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
apps/webapp/app/v3/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

In the webapp v3 directory, only modify V2 code paths when encountering V1/V2 branching in services - all new work uses Run Engine 2.0 (@internal/run-engine) and redis-worker, not legacy V1 engine code

Files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
apps/webapp/app/v3/services/**/*.server.ts

📄 CodeRabbit inference engine (apps/webapp/CLAUDE.md)

Only modify V2 code paths when editing services that branch on RunEngineVersion to support both V1 and V2 (e.g., cancelTaskRun.server.ts, batchTriggerV3.server.ts)

Files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
🧠 Learnings (26)
📓 Common learnings
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to apps/webapp/app/v3/**/*.{ts,tsx} : In the webapp v3 directory, only modify V2 code paths when encountering V1/V2 branching in services - all new work uses Run Engine 2.0 (`internal/run-engine`) and redis-worker, not legacy V1 engine code
📚 Learning: 2026-03-23T06:24:25.029Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:25.029Z
Learning: Applies to apps/webapp/app/v3/services/**/*.server.ts : Only modify V2 code paths when editing services that branch on `RunEngineVersion` to support both V1 and V2 (e.g., `cancelTaskRun.server.ts`, `batchTriggerV3.server.ts`)

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to apps/webapp/app/v3/**/*.{ts,tsx} : In the webapp v3 directory, only modify V2 code paths when encountering V1/V2 branching in services - all new work uses Run Engine 2.0 (`internal/run-engine`) and redis-worker, not legacy V1 engine code

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to packages/trigger-sdk/**/*.{ts,tsx} : In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-22T13:26:12.060Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/code/TextEditor.tsx:81-86
Timestamp: 2026-03-22T13:26:12.060Z
Learning: In the triggerdotdev/trigger.dev codebase, do not flag `navigator.clipboard.writeText(...)` calls for `missing-await`/`unhandled-promise` issues. These clipboard writes are intentionally invoked without `await` and without `catch` handlers across the project; keep that behavior consistent when reviewing TypeScript/TSX files (e.g., usages like in `apps/webapp/app/components/code/TextEditor.tsx`).

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/services/**/*.server.{ts,tsx} : Separate testable services from configuration files; follow the pattern of `realtimeClient.server.ts` (testable service) and `realtimeClientGlobal.server.ts` (configuration) in the webapp

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: The SDK at packages/trigger-sdk is an isomorphic TypeScript SDK

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2026-03-02T12:42:47.652Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/supervisor/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:47.652Z
Learning: Applies to apps/supervisor/src/workloadServer/**/*.{js,ts} : HTTP server for workload communication (heartbeats, snapshots) should be implemented in `src/workloadServer/`

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Import from `trigger.dev/sdk` (NEVER from `trigger.dev/sdk/v3`)

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to **/*.{ts,tsx} : When writing Trigger.dev tasks, always import from `trigger.dev/sdk` - never use `trigger.dev/sdk/v3` or deprecated `client.defineJob`

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:34.140Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/cli-v3/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:34.140Z
Learning: Applies to packages/cli-v3/src/build/**/* : Bundle worker code using the build system in `src/build/` based on configuration from `trigger.config.ts`

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-22T19:24:14.403Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3187
File: apps/webapp/app/v3/services/alerts/deliverErrorGroupAlert.server.ts:200-204
Timestamp: 2026-03-22T19:24:14.403Z
Learning: In the triggerdotdev/trigger.dev codebase, webhook URLs are not expected to contain embedded credentials/secrets (e.g., fields like `ProjectAlertWebhookProperties` should only hold credential-free webhook endpoints). During code review, if you see logging or inclusion of raw webhook URLs in error messages, do not automatically treat it as a credential-leak/secrets-in-logs issue by default—first verify the URL does not contain embedded credentials (for example, no username/password in the URL, no obvious secret/token query params or fragments). If the URL is credential-free per this project’s conventions, allow the logging.

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `task()` from `trigger.dev/sdk` for basic task definitions with `id` and `run` properties

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk` with a Zod schema for payload validation

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `metadata.stream()` to stream data in realtime from inside tasks

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:48.124Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/trigger-sdk/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:48.124Z
Learning: Applies to packages/trigger-sdk/**/*.{ts,tsx,js,jsx} : Always import from `trigger.dev/sdk`. Never use `trigger.dev/sdk/v3` (deprecated path alias)

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-23T06:24:25.029Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:25.029Z
Learning: Applies to apps/webapp/app/routes/**/*.ts : Use Remix flat-file route convention with dot-separated segments where `api.v1.tasks.$taskId.trigger.ts` maps to `/api/v1/tasks/:taskId/trigger`

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Use Run Engine 2.0 (`internal/run-engine`) and redis-worker for all new work instead of legacy V1 engine code

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-02T12:43:43.173Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/redis-worker/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:43.173Z
Learning: Applies to packages/redis-worker/**/*@(job|queue|worker|background).{ts,tsx} : Use trigger.dev/redis-worker for all new background job implementations, replacing graphile-worker and zodworker

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:43.173Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/redis-worker/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:43.173Z
Learning: Applies to packages/redis-worker/**/redis-worker/src/queue.ts : Job queue abstraction should be Redis-backed in src/queue.ts

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:43.173Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/redis-worker/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:43.173Z
Learning: Applies to packages/redis-worker/**/redis-worker/src/worker.ts : Worker loop and job processing should implement concurrency control in src/worker.ts

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-10T17:56:20.938Z
Learnt from: samejr
Repo: triggerdotdev/trigger.dev PR: 3201
File: apps/webapp/app/v3/services/setSeatsAddOn.server.ts:25-29
Timestamp: 2026-03-10T17:56:20.938Z
Learning: Do not implement local userId-to-organizationId authorization checks inside org-scoped service classes (e.g., SetSeatsAddOnService, SetBranchesAddOnService) in the web app. Rely on route-layer authentication (requireUserId(request)) and org membership enforcement via the _app.orgs.$organizationSlug layout route. Any userId/organizationId that reaches these services from org-scoped routes has already been validated. Apply this pattern across all org-scoped services to avoid redundant auth checks and maintain consistency.

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Use the Run Engine 2.0 from `internal/run-engine` for new run lifecycle code in the webapp instead of the legacy run engine

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: All new run lifecycle logic should be implemented in the `internal/run-engine` package (`src/engine/`), not directly in `apps/webapp/app/v3/services/`

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
🔇 Additional comments (4)
apps/webapp/app/runEngine/services/batchTrigger.server.ts (1)

19-19: Good migration to protocol-aware object-store keys.

Using the returned uploadedFilename instead of the precomputed path preserves correctness when the storage layer rewrites/ prefixes object identifiers.

Also applies to: 719-723

apps/webapp/app/v3/services/triggerTaskV1.server.ts (2)

759-763: Payload offload pointer handling looks correct.

Returning uploadedFilename here keeps stored packet references aligned with the new object-store abstraction.


29-29: This change is acceptable. TriggerTaskServiceV1 is deprecated but remains active for backward compatibility with existing V1 engine tasks. The guideline against modifying V1 code paths applies specifically to services with branching logic (e.g., cancelTaskRun.server.ts), not to maintenance and refactoring of existing V1-only implementations. The import swap to objectStore.server is a straightforward maintenance update, not new V1 feature development.

apps/webapp/app/v3/services/batchTriggerV3.server.ts (1)

28-28: Nice update for seamless object-store migration.

This correctly stores the canonical identifier returned by upload, which is required for multi-protocol object-store compatibility.

Also applies to: 933-937


Walkthrough

Replaces the R2-specific object-store implementation with a new multi-protocol object store module (apps/webapp/app/v3/objectStore.server.ts) and deletes the old r2.server.ts. Import sites were updated to use the new module and callsites now capture returned stored filenames. The new module provides protocol-prefixed URI parsing/formatting, a protocol-aware client registry, upload/download/presign APIs, and support for a configurable default upload protocol. Environment examples and documentation were extended with OBJECT_STORE_DEFAULT_PROTOCOL and protocol-prefixed provider variables (e.g., OBJECT_STORE_S3_*, OBJECT_STORE_R2_*).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Object Storage seamless migration' directly and clearly describes the main change—adding support for seamless migration to different object storage providers with multi-provider configuration.
Description check ✅ Passed The description provides a clear overview of the feature (seamless migration, multi-provider support, env var configuration) and includes a practical example, but is missing several template sections including explicit testing steps, a formal changelog entry, and the contributor checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch object-storage-migration

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.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 26, 2026

🧭 Helm Chart Prerelease Published

Version: 4.0.5-pr3275.feac4be

Install:

helm upgrade --install trigger \
  oci://ghcr.io/triggerdotdev/charts/trigger \
  --version "4.0.5-pr3275.feac4be"

⚠️ This is a prerelease for testing. Do not use in production.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (5)
apps/webapp/app/runEngine/concerns/payloads.server.ts (1)

34-45: Protocol parameter usage is correct; consider adding explicit null check.

This is correctly passing env.OBJECT_STORE_DEFAULT_PROTOCOL to enable the new multi-protocol storage feature. The tryCatch error handling pattern is appropriate.

The non-null assertion on line 43 (uploadedFilename!) relies on the assumption that a successful upload always returns a filename. While the error check on line 38 guards against uploadError, an explicit guard would be more defensive:

💡 Optional: Add explicit null check for clarity
  if (uploadError) {
    throw new ServiceValidationError("Failed to upload large payload to object store", 500);
  }

+ if (!uploadedFilename) {
+   throw new ServiceValidationError("Upload succeeded but returned no filename", 500);
+ }
+
  return {
-   data: uploadedFilename!,
+   data: uploadedFilename,
    dataType: "application/store",
  };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/runEngine/concerns/payloads.server.ts` around lines 34 - 45,
The upload result currently trusts uploadedFilename non-null via a non-null
assertion after the tryCatch call to uploadPacketToObjectStore; add an explicit
guard that checks uploadedFilename is truthy before returning and throw a
ServiceValidationError (or similar retryable error) if it's null/undefined so
callers don't receive an unexpected null value—update the block that uses
tryCatch/uploadPacketToObjectStore/uploadedFilename to validate uploadedFilename
and handle the missing filename path explicitly instead of relying on the `!`
assertion.
apps/webapp/app/runEngine/services/batchTrigger.server.ts (1)

19-19: Stylistic inconsistency in parameter passing—no functional impact.

The import path is correct. However, uploadPacketToObjectStore calls are inconsistent: some call sites (e.g., payloads.server.ts line 35, batchPayloads.server.ts line 110) explicitly pass env.OBJECT_STORE_DEFAULT_PROTOCOL, while others (including line 719 of this file) omit it.

This is a stylistic inconsistency only. The function defaults to env.OBJECT_STORE_DEFAULT_PROTOCOL when no protocol parameter is provided, so all calls use the same value regardless. For uniformity, consider aligning all calls to either pass the parameter explicitly or rely on the default consistently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/runEngine/services/batchTrigger.server.ts` at line 19, Calls
to uploadPacketToObjectStore are stylistically inconsistent: some callers pass
env.OBJECT_STORE_DEFAULT_PROTOCOL explicitly while others (e.g., in
batchTrigger.server.ts) omit it. Pick one convention and apply it project-wide;
for minimal churn, update the omitted call sites (including the call in
batchTrigger.server.ts) to pass env.OBJECT_STORE_DEFAULT_PROTOCOL as the
protocol argument to uploadPacketToObjectStore so all usages are explicit and
consistent.
apps/webapp/app/runEngine/concerns/batchPayloads.server.ts (2)

8-17: Update type comments to reflect the generic object storage implementation.

The type comments still reference "R2" specifically, but the implementation now supports multiple protocols. Consider updating for accuracy:

  • Line 9: "R2 path" → "object storage path"
  • Line 11: "offloaded to R2" → "offloaded to object storage"
  • Line 13: "offloaded to R2" → "offloaded to object storage"
📝 Suggested comment updates
 export type BatchPayloadProcessResult = {
-  /** The processed payload - either the original or an R2 path */
+  /** The processed payload - either the original or an object storage path */
   payload: unknown;
-  /** The payload type - "application/store" if offloaded to R2 */
+  /** The payload type - "application/store" if offloaded to object storage */
   payloadType: string;
-  /** Whether the payload was offloaded to R2 */
+  /** Whether the payload was offloaded to object storage */
   wasOffloaded: boolean;
   /** Size of the payload in bytes */
   size: number;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/runEngine/concerns/batchPayloads.server.ts` around lines 8 -
17, Update the JSDoc comments on the BatchPayloadProcessResult type to remove
R2-specific wording and reference the generic object storage implementation:
change "R2 path" to "object storage path" in the payload comment, change
"offloaded to R2" to "offloaded to object storage" in the payloadType and
wasOffloaded comments, ensuring the comments next to payload, payloadType and
wasOffloaded reflect the generic object storage terminology.

19-27: Similar R2-specific references in class JSDoc.

The class documentation also mentions R2 specifically on lines 23 and could be generalized.

📝 Suggested comment update
 /**
  * BatchPayloadProcessor handles payload offloading for batch items.
  *
  * When a batch item's payload exceeds the configured threshold, it's uploaded
- * to object storage (R2) and the payload is replaced with the storage path.
+ * to object storage and the payload is replaced with the storage path.
  * This aligns with how single task triggers work via DefaultPayloadProcessor.
  *
  * Path format: batch_{batchId}/item_{index}/payload.json
  */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/runEngine/concerns/batchPayloads.server.ts` around lines 19 -
27, The JSDoc for BatchPayloadProcessor mentions R2 specifically; update the
class comment to generalize storage references (e.g., "object storage" or
"external storage") and keep the path format note. Modify the JSDoc above the
BatchPayloadProcessor class to remove R2-specific wording and replace it with a
neutral term like "object storage (e.g., R2)" while preserving the explanation
of offloading behavior and the Path format:
batch_{batchId}/item_{index}/payload.json so the docs remain accurate across
storage backends.
apps/webapp/app/v3/objectStore.server.ts (1)

67-88: Direct process.env access bypasses validation - document this intentionally.

The protocol-specific environment variables are accessed via process.env directly (lines 71-75), bypassing the zod validation in env.server.ts. This is intentional since protocol names are dynamic, but consider adding a comment explaining this design choice.

As per coding guidelines: "Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp"

📝 Add documentation comment
 function getObjectStoreConfig(protocol?: string): ObjectStoreConfig | undefined {
   if (protocol) {
-    // Named provider (e.g., OBJECT_STORE_S3_*)
+    // Named provider (e.g., OBJECT_STORE_S3_*)
+    // Note: We access process.env directly here because protocol names are dynamic
+    // and cannot be pre-defined in the zod schema. Validation is done inline below.
     const prefix = `OBJECT_STORE_${protocol.toUpperCase()}_`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/v3/objectStore.server.ts` around lines 67 - 88,
getObjectStoreConfig currently reads protocol-specific environment variables
directly from process.env (ACCESS_KEY_ID, SECRET_ACCESS_KEY, BASE_URL, REGION,
SERVICE) which intentionally bypasses zod validation in env.server.ts because
protocol names are dynamic; add a short explanatory comment above the
getObjectStoreConfig function stating that dynamic protocol prefixes prevent
static env.schema validation, that direct process.env access is intentional and
reviewed, and include a pointer to env.server.ts so future maintainers know
where validated env vars live and why this exception exists (mention
getObjectStoreConfig and env.server.ts by name).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/webapp/app/v3/objectStore.server.ts`:
- Around line 294-296: The URL pathname currently uses prefix directly, which
produces "undefined/filename" when prefix is undefined; update the URL pathname
construction in the function that builds the object URL so it only includes
prefix when it is truthy and ensures a single leading slash. Concretely, build
the pathname by joining prefix and filename only when prefix exists (skip or
omit prefix if undefined/empty), ensure you add a single leading '/' to the
resulting pathname, and replace the current direct assignment to url.pathname
with this conditional join logic so filename is always correct and no
"undefined" appears.

In `@docs/self-hosting/env/webapp.mdx`:
- Around line 243-248: The MDX Step block is malformed: the bullet lines inside
Step use leading dashes/indentation that breaks MDX parsing and the closing
</Step> is indented on the same line as content; fix by removing the conflicting
leading dashes/extra indentation so the three items are plain list lines (or a
proper Markdown list) inside the Step component and place the closing </Step>
tag on its own line; target the Step block that contains the lines "New data
uses `s3://` prefix...", "Old data (no prefix) still uses R2", and "Data with
explicit protocol uses the corresponding provider" and reformat those lines and
</Step> accordingly.
- Around line 231-234: The Step titled "Test the configuration" contains leading
hyphens that are being parsed as list markers and breaking the content; edit the
content inside Step title="Test the configuration" and either convert those
lines into a proper Markdown list (each item on its own line prefixed with a
single hyphen and a blank line before the list) or remove the leading hyphens
and make them full sentences (e.g., "Old runs (no prefix) should still access
R2." and "New runs with `s3://` prefix should use S3."), ensuring the inline
code `s3://` remains backticked and the Step content is valid MDX.

---

Nitpick comments:
In `@apps/webapp/app/runEngine/concerns/batchPayloads.server.ts`:
- Around line 8-17: Update the JSDoc comments on the BatchPayloadProcessResult
type to remove R2-specific wording and reference the generic object storage
implementation: change "R2 path" to "object storage path" in the payload
comment, change "offloaded to R2" to "offloaded to object storage" in the
payloadType and wasOffloaded comments, ensuring the comments next to payload,
payloadType and wasOffloaded reflect the generic object storage terminology.
- Around line 19-27: The JSDoc for BatchPayloadProcessor mentions R2
specifically; update the class comment to generalize storage references (e.g.,
"object storage" or "external storage") and keep the path format note. Modify
the JSDoc above the BatchPayloadProcessor class to remove R2-specific wording
and replace it with a neutral term like "object storage (e.g., R2)" while
preserving the explanation of offloading behavior and the Path format:
batch_{batchId}/item_{index}/payload.json so the docs remain accurate across
storage backends.

In `@apps/webapp/app/runEngine/concerns/payloads.server.ts`:
- Around line 34-45: The upload result currently trusts uploadedFilename
non-null via a non-null assertion after the tryCatch call to
uploadPacketToObjectStore; add an explicit guard that checks uploadedFilename is
truthy before returning and throw a ServiceValidationError (or similar retryable
error) if it's null/undefined so callers don't receive an unexpected null
value—update the block that uses
tryCatch/uploadPacketToObjectStore/uploadedFilename to validate uploadedFilename
and handle the missing filename path explicitly instead of relying on the `!`
assertion.

In `@apps/webapp/app/runEngine/services/batchTrigger.server.ts`:
- Line 19: Calls to uploadPacketToObjectStore are stylistically inconsistent:
some callers pass env.OBJECT_STORE_DEFAULT_PROTOCOL explicitly while others
(e.g., in batchTrigger.server.ts) omit it. Pick one convention and apply it
project-wide; for minimal churn, update the omitted call sites (including the
call in batchTrigger.server.ts) to pass env.OBJECT_STORE_DEFAULT_PROTOCOL as the
protocol argument to uploadPacketToObjectStore so all usages are explicit and
consistent.

In `@apps/webapp/app/v3/objectStore.server.ts`:
- Around line 67-88: getObjectStoreConfig currently reads protocol-specific
environment variables directly from process.env (ACCESS_KEY_ID,
SECRET_ACCESS_KEY, BASE_URL, REGION, SERVICE) which intentionally bypasses zod
validation in env.server.ts because protocol names are dynamic; add a short
explanatory comment above the getObjectStoreConfig function stating that dynamic
protocol prefixes prevent static env.schema validation, that direct process.env
access is intentional and reviewed, and include a pointer to env.server.ts so
future maintainers know where validated env vars live and why this exception
exists (mention getObjectStoreConfig and env.server.ts by name).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a5fb6d1f-5779-447a-96f3-28cd89876955

📥 Commits

Reviewing files that changed from the base of the PR and between 922a852 and 7687d97.

📒 Files selected for processing (15)
  • .env.example
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
  • apps/webapp/app/v3/r2.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • docs/self-hosting/env/webapp.mdx
  • hosting/docker/.env.example
  • hosting/k8s/helm/values.yaml
💤 Files with no reviewable changes (1)
  • apps/webapp/app/v3/r2.server.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: sdk-compat / Bun Runtime
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: For apps and internal packages (apps/*, internal-packages/*), use pnpm run typecheck --filter <package> for verification, never use build as it proves almost nothing about correctness
Use testcontainers helpers (redisTest, postgresTest, containerTest from @internal/testcontainers) for integration tests with Redis and PostgreSQL instead of mocking
When writing Trigger.dev tasks, always import from @trigger.dev/sdk - never use @trigger.dev/sdk/v3 or deprecated client.defineJob

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

**/*.{ts,tsx,js,jsx}: Use pnpm for package management in this monorepo (version 10.23.0) with Turborepo for orchestration - run commands from root with pnpm run
Add crumbs as you write code for debug tracing using // @Crumbs comments or `// `#region` `@crumbs blocks - they stay on the branch throughout development and are stripped via agentcrumbs strip before merge

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • hosting/k8s/helm/values.yaml
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
apps/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When modifying only server components (apps/webapp/, apps/supervisor/, etc.) with no package changes, add a .server-changes/ file instead of a changeset

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
apps/webapp/app/**/*.{ts,tsx,server.ts}

📄 CodeRabbit inference engine (apps/webapp/CLAUDE.md)

Access environment variables via env export from app/env.server.ts. Never use process.env directly

Files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
apps/webapp/app/routes/**/*.ts

📄 CodeRabbit inference engine (apps/webapp/CLAUDE.md)

Use Remix flat-file route convention with dot-separated segments where api.v1.tasks.$taskId.trigger.ts maps to /api/v1/tasks/:taskId/trigger

Files:

  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
apps/webapp/app/v3/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Organize services in the webapp following the pattern app/v3/services/*/*.server.ts

Files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
apps/webapp/app/v3/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

In the webapp v3 directory, only modify V2 code paths when encountering V1/V2 branching in services - all new work uses Run Engine 2.0 (@internal/run-engine) and redis-worker, not legacy V1 engine code

Files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
apps/webapp/app/v3/services/**/*.server.ts

📄 CodeRabbit inference engine (apps/webapp/CLAUDE.md)

Only modify V2 code paths when editing services that branch on RunEngineVersion to support both V1 and V2 (e.g., cancelTaskRun.server.ts, batchTriggerV3.server.ts)

Files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
docs/**/*.mdx

📄 CodeRabbit inference engine (docs/CLAUDE.md)

docs/**/*.mdx: MDX documentation pages must include frontmatter with title (required), description (required), and sidebarTitle (optional) in YAML format
Use Mintlify components for structured content: , , , , , , /, /
Always import from @trigger.dev/sdk in code examples (never from @trigger.dev/sdk/v3)
Code examples must be complete and runnable where possible
Use language tags in code fences: typescript, bash, json

Files:

  • docs/self-hosting/env/webapp.mdx
🧠 Learnings (54)
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/v3/presenters/**/*.server.{ts,tsx} : Organize presenters in the webapp following the pattern `app/v3/presenters/*/*.server.ts` to move complex loader code into classes

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
📚 Learning: 2026-03-23T06:24:25.029Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:25.029Z
Learning: Applies to apps/webapp/app/v3/services/**/*.server.ts : Only modify V2 code paths when editing services that branch on `RunEngineVersion` to support both V1 and V2 (e.g., `cancelTaskRun.server.ts`, `batchTriggerV3.server.ts`)

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to apps/webapp/app/v3/**/*.{ts,tsx} : In the webapp v3 directory, only modify V2 code paths when encountering V1/V2 branching in services - all new work uses Run Engine 2.0 (`internal/run-engine`) and redis-worker, not legacy V1 engine code

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: All new run lifecycle logic should be implemented in the `internal/run-engine` package (`src/engine/`), not directly in `apps/webapp/app/v3/services/`

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Use the Run Engine 2.0 from `internal/run-engine` for new run lifecycle code in the webapp instead of the legacy run engine

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-02T12:43:17.177Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:17.177Z
Learning: Applies to internal-packages/database/**/{app,src,webapp}/**/*.{ts,tsx,js,jsx} : Use `$replica` from `~/db.server` for read-heavy queries in the webapp instead of the primary database connection

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Use Prisma for data persistence with support for read-only replica queries via `readOnlyPrisma`

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
📚 Learning: 2026-03-02T12:43:17.177Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:17.177Z
Learning: New code should always target Prisma RunEngineVersion V2 (run-engine + redis-worker), not V1 (legacy MarQS + Graphile)

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
📚 Learning: 2026-02-06T19:53:38.843Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: apps/webapp/app/presenters/v3/DeploymentListPresenter.server.ts:233-237
Timestamp: 2026-02-06T19:53:38.843Z
Learning: When constructing Vercel dashboard URLs from deployment IDs, always strip the dpl_ prefix from the ID. Implement this by transforming the ID with .replace(/^dpl_/, "") before concatenating into the URL: https://vercel.com/${teamSlug}/${projectName}/${cleanedDeploymentId}. Consider centralizing this logic in a small helper (e.g., getVercelDeploymentId(id) or a URL builder) and add tests to verify both prefixed and non-prefixed inputs.

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
📚 Learning: 2026-03-22T13:26:12.060Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/code/TextEditor.tsx:81-86
Timestamp: 2026-03-22T13:26:12.060Z
Learning: In the triggerdotdev/trigger.dev codebase, do not flag `navigator.clipboard.writeText(...)` calls for `missing-await`/`unhandled-promise` issues. These clipboard writes are intentionally invoked without `await` and without `catch` handlers across the project; keep that behavior consistent when reviewing TypeScript/TSX files (e.g., usages like in `apps/webapp/app/components/code/TextEditor.tsx`).

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
📚 Learning: 2026-03-22T19:24:14.403Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3187
File: apps/webapp/app/v3/services/alerts/deliverErrorGroupAlert.server.ts:200-204
Timestamp: 2026-03-22T19:24:14.403Z
Learning: In the triggerdotdev/trigger.dev codebase, webhook URLs are not expected to contain embedded credentials/secrets (e.g., fields like `ProjectAlertWebhookProperties` should only hold credential-free webhook endpoints). During code review, if you see logging or inclusion of raw webhook URLs in error messages, do not automatically treat it as a credential-leak/secrets-in-logs issue by default—first verify the URL does not contain embedded credentials (for example, no username/password in the URL, no obvious secret/token query params or fragments). If the URL is credential-free per this project’s conventions, allow the logging.

Applied to files:

  • apps/webapp/app/presenters/v3/ApiRetrieveRunPresenter.server.ts
  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/payloads.server.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/objectStore.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
📚 Learning: 2026-02-04T16:34:48.876Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: apps/webapp/app/routes/vercel.connect.tsx:13-27
Timestamp: 2026-02-04T16:34:48.876Z
Learning: In apps/webapp/app/routes/vercel.connect.tsx, configurationId may be absent for "dashboard" flows but must be present for "marketplace" flows. Enforce this with a Zod superRefine and pass installationId to repository methods only when configurationId is defined (omit the field otherwise).

Applied to files:

  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to {packages/core,apps/webapp}/**/*.{ts,tsx} : Use zod for validation in packages/core and apps/webapp

Applied to files:

  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
  • apps/webapp/app/routes/api.v1.packets.$.ts
📚 Learning: 2026-03-02T12:43:17.177Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:17.177Z
Learning: Edit Prisma schema at `prisma/schema.prisma` and generate migrations using `pnpm run db:migrate:dev:create --name "descriptive_name"` from the `internal-packages/database` directory

Applied to files:

  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
📚 Learning: 2026-03-13T13:42:59.104Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3213
File: apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts:40-43
Timestamp: 2026-03-13T13:42:59.104Z
Learning: In `apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts` and `apps/webapp/app/routes/admin.api.v1.llm-models.ts`, the `startDate` field in `UpdateModelSchema` and `CreateModelSchema` intentionally uses `z.string().optional()` (or `.nullable().optional()`) without strict ISO datetime validation. Invalid date strings are rejected at the Prisma/DB layer. This is acceptable because these are admin-only API routes protected by Personal Access Token (PAT) authentication and are not user-facing.

Applied to files:

  • apps/webapp/app/routes/resources.packets.$environmentId.$.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `batch.triggerByTask()` to batch trigger multiple tasks by passing task instances

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `task.batchTrigger()` to trigger multiple runs of a task from inside another task

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to packages/trigger-sdk/**/*.{ts,tsx} : In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:34.140Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/cli-v3/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:34.140Z
Learning: Applies to packages/cli-v3/src/build/**/* : Bundle worker code using the build system in `src/build/` based on configuration from `trigger.config.ts`

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `batch.triggerByTaskAndWait()` to batch trigger multiple tasks by instance and wait for results

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/v3/services/**/*.server.{ts,tsx} : Organize services in the webapp following the pattern `app/v3/services/*/*.server.ts`

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to **/*.{ts,tsx} : When writing Trigger.dev tasks, always import from `trigger.dev/sdk` - never use `trigger.dev/sdk/v3` or deprecated `client.defineJob`

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `batch.triggerAndWait()` to trigger multiple different tasks and wait for all results

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/concerns/batchPayloads.server.ts
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Use Run Engine 2.0 (`internal/run-engine`) and redis-worker for all new work instead of legacy V1 engine code

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:42:47.652Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/supervisor/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:47.652Z
Learning: Applies to apps/supervisor/src/workloadServer/**/*.{js,ts} : HTTP server for workload communication (heartbeats, snapshots) should be implemented in `src/workloadServer/`

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-10T17:56:20.938Z
Learnt from: samejr
Repo: triggerdotdev/trigger.dev PR: 3201
File: apps/webapp/app/v3/services/setSeatsAddOn.server.ts:25-29
Timestamp: 2026-03-10T17:56:20.938Z
Learning: Do not implement local userId-to-organizationId authorization checks inside org-scoped service classes (e.g., SetSeatsAddOnService, SetBranchesAddOnService) in the web app. Rely on route-layer authentication (requireUserId(request)) and org membership enforcement via the _app.orgs.$organizationSlug layout route. Any userId/organizationId that reaches these services from org-scoped routes has already been validated. Apply this pattern across all org-scoped services to avoid redundant auth checks and maintain consistency.

Applied to files:

  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • apps/webapp/app/env.server.ts
📚 Learning: 2026-03-23T06:24:25.028Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:25.028Z
Learning: Applies to apps/webapp/app/**/*.{ts,tsx,server.ts} : Access environment variables via `env` export from `app/env.server.ts`. Never use `process.env` directly

Applied to files:

  • apps/webapp/app/env.server.ts
📚 Learning: 2026-03-02T12:42:47.652Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/supervisor/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:47.652Z
Learning: Applies to apps/supervisor/src/env.ts : Environment configuration should be defined in `src/env.ts`

Applied to files:

  • apps/webapp/app/env.server.ts
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to apps/**/*.{ts,tsx,js,jsx} : When modifying only server components (`apps/webapp/`, `apps/supervisor/`, etc.) with no package changes, add a `.server-changes/` file instead of a changeset

Applied to files:

  • apps/webapp/app/env.server.ts
📚 Learning: 2026-03-23T06:24:25.028Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:25.028Z
Learning: Applies to apps/webapp/**/*.{test,spec}.{ts,tsx} : For testable code, never import `env.server.ts` in test files. Pass configuration as options/constructor arguments instead

Applied to files:

  • apps/webapp/app/env.server.ts
📚 Learning: 2026-03-06T14:44:55.489Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3173
File: packages/trigger-sdk/src/v3/chat.test.ts:103-104
Timestamp: 2026-03-06T14:44:55.489Z
Learning: In `packages/trigger-sdk/src/v3/chat.test.ts`, mocking `global.fetch` with `vi.fn()` is acceptable and intentional. `TriggerChatTransport` is a browser-facing SSE/HTTP client, and using testcontainers for these tests is not required. This file is an explicit exception to the repo's general no-mocks policy.

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2026-03-02T12:43:48.124Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/trigger-sdk/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:48.124Z
Learning: Applies to packages/trigger-sdk/**/*.{ts,tsx,js,jsx} : Always import from `trigger.dev/sdk`. Never use `trigger.dev/sdk/v3` (deprecated path alias)

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/app/services/**/*.server.{ts,tsx} : Separate testable services from configuration files; follow the pattern of `realtimeClient.server.ts` (testable service) and `realtimeClientGlobal.server.ts` (configuration) in the webapp

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: The SDK at packages/trigger-sdk is an isomorphic TypeScript SDK

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Import from `trigger.dev/sdk` (NEVER from `trigger.dev/sdk/v3`)

Applied to files:

  • apps/webapp/app/runEngine/services/batchTrigger.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Set the `TRIGGER_SECRET_KEY` environment variable when triggering tasks from backend code (available on the API keys page in the Trigger.dev dashboard)

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2025-06-25T13:20:17.174Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2195
File: hosting/k8s/helm/values.yaml:22-51
Timestamp: 2025-06-25T13:20:17.174Z
Learning: In the Trigger.dev Helm chart values.yaml, the maintainer prefers to use explicit comprehensive warnings for security-sensitive default values rather than implementing secure-by-default behavior that would fail installation. The project uses deterministic default secrets with clear "TESTING ONLY" warnings and instructions for production deployment.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2025-11-10T09:09:07.399Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2663
File: apps/webapp/app/env.server.ts:1205-1206
Timestamp: 2025-11-10T09:09:07.399Z
Learning: In the trigger.dev webapp, S2_ACCESS_TOKEN and S2_DEPLOYMENT_LOGS_BASIN_NAME environment variables must remain optional until an OSS version of S2 is available, to avoid breaking environments that don't have S2 provisioned.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
  • hosting/docker/.env.example
  • .env.example
📚 Learning: 2025-06-25T14:14:11.965Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2195
File: hosting/k8s/helm/values-production-example.yaml:95-102
Timestamp: 2025-06-25T14:14:11.965Z
Learning: In the Trigger.dev Helm chart production examples, the maintainer prefers to include initial/bootstrap credentials with clear warnings that they should be changed after first login, rather than requiring external secret references that could complicate initial setup. This follows their pattern of providing working examples with explicit security guidance.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
  • hosting/docker/.env.example
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to trigger.config.ts : Configure the Trigger.dev project using `defineConfig()` with properties like `project`, `dirs`, `retries`, `runtime`, and `build`

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2026-03-10T12:44:14.176Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 3200
File: docs/config/config-file.mdx:353-368
Timestamp: 2026-03-10T12:44:14.176Z
Learning: In the trigger.dev repo, docs PRs are often companions to implementation PRs. When reviewing docs PRs (MDX files under docs/), check the PR description for any companion/related PR references and verify that the documented features exist in those companion PRs before flagging missing implementations. This ensures docs stay in sync with code changes across related PRs.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2025-06-06T23:55:01.933Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2155
File: hosting/docker/.env.example:4-7
Timestamp: 2025-06-06T23:55:01.933Z
Learning: In the trigger.dev project, .env.example files should contain actual example secret values rather than placeholders, as these help users understand the expected format. The files include clear warnings about not using these defaults in production and instructions for generating proper secrets.

Applied to files:

  • hosting/docker/.env.example
  • .env.example
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `task()` from `trigger.dev/sdk` for basic task definitions with `id` and `run` properties

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk` with a Zod schema for payload validation

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-23T06:24:25.029Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:25.029Z
Learning: Applies to apps/webapp/app/routes/**/*.ts : Use Remix flat-file route convention with dot-separated segments where `api.v1.tasks.$taskId.trigger.ts` maps to `/api/v1/tasks/:taskId/trigger`

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export every task, including subtasks

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:43.173Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/redis-worker/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:43.173Z
Learning: Applies to packages/redis-worker/**/*@(job|queue|worker|background).{ts,tsx} : Use trigger.dev/redis-worker for all new background job implementations, replacing graphile-worker and zodworker

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:43.173Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/redis-worker/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:43.173Z
Learning: Applies to packages/redis-worker/**/redis-worker/src/queue.ts : Job queue abstraction should be Redis-backed in src/queue.ts

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2026-03-02T12:43:43.173Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: packages/redis-worker/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:43.173Z
Learning: Applies to packages/redis-worker/**/redis-worker/src/worker.ts : Worker loop and job processing should implement concurrency control in src/worker.ts

Applied to files:

  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
📚 Learning: 2025-07-12T18:00:06.163Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2264
File: apps/webapp/app/utils/searchParams.ts:16-18
Timestamp: 2025-07-12T18:00:06.163Z
Learning: The `objectToSearchParams` function in `apps/webapp/app/utils/searchParams.ts` is used to generate URL parameters from objects and is separate from code that parses incoming search parameters. Changes to this function only affect places where it's used to create URLs, not places that parse search parameters from external sources.

Applied to files:

  • apps/webapp/app/v3/objectStore.server.ts
🪛 GitHub Actions: 📚 Docs Checks
docs/self-hosting/env/webapp.mdx

[error] 248-248: Mintlify broken-links check failed: Syntax error - Unable to parse self-hosting/env/webapp.mdx at 248:3-248:10. Expected the closing tag </Step> either after the end of listItem (248:10) or another opening tag after the start of listItem (247:1).

🪛 LanguageTool
docs/self-hosting/env/webapp.mdx

[style] ~14-~14: To form a complete sentence, be sure to include a subject.
Context: ...-secret | Managed worker secret. Should be changed and match supervisor. ...

(MISSING_IT_THERE)

Comment on lines +294 to +296
const url = new URL(config.baseUrl);
url.pathname = `${prefix}/${filename}`;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle undefined prefix in URL pathname construction.

When prefix is undefined, the pathname becomes "undefined/${filename}" which is incorrect. The function signature shows prefix is optional (line 270).

🐛 Proposed fix
     const url = new URL(config.baseUrl);
-    url.pathname = `${prefix}/${filename}`;
+    url.pathname = prefix ? `${prefix}/${filename}` : `/${filename}`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const url = new URL(config.baseUrl);
url.pathname = `${prefix}/${filename}`;
const url = new URL(config.baseUrl);
url.pathname = prefix ? `${prefix}/${filename}` : `/${filename}`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/webapp/app/v3/objectStore.server.ts` around lines 294 - 296, The URL
pathname currently uses prefix directly, which produces "undefined/filename"
when prefix is undefined; update the URL pathname construction in the function
that builds the object URL so it only includes prefix when it is truthy and
ensures a single leading slash. Concretely, build the pathname by joining prefix
and filename only when prefix exists (skip or omit prefix if undefined/empty),
ensure you add a single leading '/' to the resulting pathname, and replace the
current direct assignment to url.pathname with this conditional join logic so
filename is always correct and no "undefined" appears.

Copy link
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 3 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

import { logger } from "~/services/logger.server";
import { batchTriggerWorker } from "~/v3/batchTriggerWorker.server";
import { downloadPacketFromObjectStore, uploadPacketToObjectStore } from "../../v3/r2.server";
import { downloadPacketFromObjectStore, uploadPacketToObjectStore } from "../../v3/objectStore.server";
Copy link
Contributor

Choose a reason for hiding this comment

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

🔴 Three #handlePayloadPacket callers ignore uploadPacketToObjectStore return value, losing the protocol prefix

The uploadPacketToObjectStore function now internally defaults to env.OBJECT_STORE_DEFAULT_PROTOCOL when no explicit protocol is passed (objectStore.server.ts:159), and returns a protocol-prefixed filename (e.g., s3://batch/batch_xxx/payload.json). However, three #handlePayloadPacket methods were not updated to capture this return value — they still store the raw filename without the protocol prefix.

When OBJECT_STORE_DEFAULT_PROTOCOL is configured (e.g., s3) and the named provider is different from the default provider, the upload goes to the named provider (S3), but the stored reference lacks the s3:// prefix. Later, downloadPacketFromObjectStore calls parseStorageUri(packet.data) which finds no protocol prefix, so it attempts to download from the default provider (e.g., R2) — which doesn't have the data, causing retrieval failures.

Affected files (all three have the same pattern)
  • apps/webapp/app/runEngine/services/batchTrigger.server.ts:719-724
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts:933-938
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts:759-764

All three do:

await uploadPacketToObjectStore(filename, packet.data, packet.dataType, environment);
return { data: filename, dataType: "application/store" };

But should capture the return value like the updated callers in payloads.server.ts and batchPayloads.server.ts do.

Prompt for agents
Three #handlePayloadPacket methods need to be updated to capture the return value of uploadPacketToObjectStore (which now returns a protocol-prefixed filename when OBJECT_STORE_DEFAULT_PROTOCOL is set). The same fix pattern needs to be applied in all three files:

1. apps/webapp/app/runEngine/services/batchTrigger.server.ts lines 719-724:
Change:
  await uploadPacketToObjectStore(filename, packet.data, packet.dataType, environment);
  return { data: filename, dataType: "application/store" };
To:
  const uploadedFilename = await uploadPacketToObjectStore(filename, packet.data, packet.dataType, environment);
  return { data: uploadedFilename, dataType: "application/store" };

2. apps/webapp/app/v3/services/batchTriggerV3.server.ts lines 933-938:
Change:
  await uploadPacketToObjectStore(filename, packet.data, packet.dataType, environment);
  return { data: filename, dataType: "application/store" };
To:
  const uploadedFilename = await uploadPacketToObjectStore(filename, packet.data, packet.dataType, environment);
  return { data: uploadedFilename, dataType: "application/store" };

3. apps/webapp/app/v3/services/triggerTaskV1.server.ts lines 759-764:
Change:
  await uploadPacketToObjectStore(filename, packet.data, packet.dataType, environment);
  return { data: filename, dataType: "application/store" };
To:
  const uploadedFilename = await uploadPacketToObjectStore(filename, packet.data, packet.dataType, environment);
  return { data: uploadedFilename, dataType: "application/store" };
Open in Devin Review

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

Comment on lines +147 to +149
export function hasObjectStoreClient(): boolean {
return getObjectStoreClient() !== undefined;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🔴 hasObjectStoreClient() only checks default provider, ignoring named providers set via OBJECT_STORE_DEFAULT_PROTOCOL

hasObjectStoreClient() at objectStore.server.ts:147-149 calls getObjectStoreClient() with no arguments, which only checks the default (unprefixed) provider. However, BatchPayloadProcessor.isObjectStoreAvailable() at batchPayloads.server.ts:34 uses this to decide whether to attempt offloading, while the actual upload at batchPayloads.server.ts:110-116 passes env.OBJECT_STORE_DEFAULT_PROTOCOL — which uses a named provider.

If a user configures only a named provider (e.g., OBJECT_STORE_S3_*) with OBJECT_STORE_DEFAULT_PROTOCOL=s3 but no default OBJECT_STORE_* credentials, hasObjectStoreClient() returns false and batch payloads are never offloaded, even though the named provider is fully configured and the upload function would succeed.

Suggested change
export function hasObjectStoreClient(): boolean {
return getObjectStoreClient() !== undefined;
}
export function hasObjectStoreClient(): boolean {
return getObjectStoreClient() !== undefined || getObjectStoreClient(env.OBJECT_STORE_DEFAULT_PROTOCOL) !== undefined;
}
Open in Devin Review

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

Comment on lines +266 to +312
export async function uploadDataToObjectStore(
filename: string,
data: string,
contentType: string,
prefix?: string,
storageProtocol?: string
): Promise<string> {
return await startActiveSpan("uploadDataToObjectStore()", async (span) => {
const protocol = storageProtocol || env.OBJECT_STORE_DEFAULT_PROTOCOL;
const client = getObjectStoreClient(protocol);

if (!client) {
throw new Error(
`Object store credentials are not set for protocol: ${protocol || "default"}`
);
}

const config = getObjectStoreConfig(protocol);
if (!config?.baseUrl) {
throw new Error(`Object store base URL is not set for protocol: ${protocol || "default"}`);
}

span.setAttributes({
prefix,
filename,
protocol: protocol || "default",
});

const url = new URL(config.baseUrl);
url.pathname = `${prefix}/${filename}`;

logger.debug("Uploading to object store", { url: url.href, protocol: protocol || "default" });

const response = await client.fetch(url.toString(), {
method: "PUT",
headers: {
"Content-Type": contentType,
},
body: data,
});

if (!response.ok) {
throw new Error(`Failed to upload data to ${url}: ${response.statusText}`);
}

return url.href;
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🚩 uploadDataToObjectStore does not return protocol-prefixed URI

The uploadDataToObjectStore function at objectStore.server.ts:311 returns url.href (the full URL), not a protocol-prefixed filename like uploadPacketToObjectStore does. This is an inconsistency between the two upload functions. uploadPacketToObjectStore returns formatStorageUri(filename, protocol) while uploadDataToObjectStore returns the full URL. This matches the old behavior (the old uploadDataToObjectStore also returned url.href), so it's not a regression. However, if uploadDataToObjectStore callers ever need protocol-aware storage references, this would need to be updated.

Open in Devin Review

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/self-hosting/env/webapp.mdx`:
- Around line 113-114: The docs table contains duplicate environment variable
rows for MAXIMUM_DEV_QUEUE_SIZE and MAXIMUM_DEPLOYED_QUEUE_SIZE; remove the
second occurrences under the "Run engine" section (the duplicate table rows
referencing MAXIMUM_DEV_QUEUE_SIZE and MAXIMUM_DEPLOYED_QUEUE_SIZE) so each
environment variable appears only once in the document and the tables remain
consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2527a58f-ad1e-4fd0-bcdb-24ea0e4fc34b

📥 Commits

Reviewing files that changed from the base of the PR and between 7687d97 and e1d2387.

📒 Files selected for processing (1)
  • docs/self-hosting/env/webapp.mdx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (26)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
🧰 Additional context used
📓 Path-based instructions (1)
docs/**/*.mdx

📄 CodeRabbit inference engine (docs/CLAUDE.md)

docs/**/*.mdx: MDX documentation pages must include frontmatter with title (required), description (required), and sidebarTitle (optional) in YAML format
Use Mintlify components for structured content: , , , , , , /, /
Always import from @trigger.dev/sdk in code examples (never from @trigger.dev/sdk/v3)
Code examples must be complete and runnable where possible
Use language tags in code fences: typescript, bash, json

Files:

  • docs/self-hosting/env/webapp.mdx
🧠 Learnings (8)
📚 Learning: 2026-03-02T12:43:02.539Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:02.539Z
Learning: Applies to docs/**/*.mdx : Use Mintlify components for structured content: <Note>, <Warning>, <Info>, <Tip>, <CodeGroup>, <Expandable>, <Steps>/<Step>, <Card>/<CardGroup>

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2026-03-02T12:43:02.539Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:02.539Z
Learning: Applies to docs/**/*.mdx : Code examples must be complete and runnable where possible

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Set the `TRIGGER_SECRET_KEY` environment variable when triggering tasks from backend code (available on the API keys page in the Trigger.dev dashboard)

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2025-06-25T13:20:17.174Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2195
File: hosting/k8s/helm/values.yaml:22-51
Timestamp: 2025-06-25T13:20:17.174Z
Learning: In the Trigger.dev Helm chart values.yaml, the maintainer prefers to use explicit comprehensive warnings for security-sensitive default values rather than implementing secure-by-default behavior that would fail installation. The project uses deterministic default secrets with clear "TESTING ONLY" warnings and instructions for production deployment.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2025-11-10T09:09:07.399Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2663
File: apps/webapp/app/env.server.ts:1205-1206
Timestamp: 2025-11-10T09:09:07.399Z
Learning: In the trigger.dev webapp, S2_ACCESS_TOKEN and S2_DEPLOYMENT_LOGS_BASIN_NAME environment variables must remain optional until an OSS version of S2 is available, to avoid breaking environments that don't have S2 provisioned.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2025-06-25T14:14:11.965Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2195
File: hosting/k8s/helm/values-production-example.yaml:95-102
Timestamp: 2025-06-25T14:14:11.965Z
Learning: In the Trigger.dev Helm chart production examples, the maintainer prefers to include initial/bootstrap credentials with clear warnings that they should be changed after first login, rather than requiring external secret references that could complicate initial setup. This follows their pattern of providing working examples with explicit security guidance.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2026-03-25T15:29:25.853Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2026-03-25T15:29:25.853Z
Learning: Applies to trigger.config.ts : Configure the Trigger.dev project using `defineConfig()` with properties like `project`, `dirs`, `retries`, `runtime`, and `build`

Applied to files:

  • docs/self-hosting/env/webapp.mdx
📚 Learning: 2026-03-10T12:44:14.176Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 3200
File: docs/config/config-file.mdx:353-368
Timestamp: 2026-03-10T12:44:14.176Z
Learning: In the trigger.dev repo, docs PRs are often companions to implementation PRs. When reviewing docs PRs (MDX files under docs/), check the PR description for any companion/related PR references and verify that the documented features exist in those companion PRs before flagging missing implementations. This ensures docs stay in sync with code changes across related PRs.

Applied to files:

  • docs/self-hosting/env/webapp.mdx
🪛 LanguageTool
docs/self-hosting/env/webapp.mdx

[style] ~14-~14: To form a complete sentence, be sure to include a subject.
Context: ...-secret | Managed worker secret. Should be changed and match supervisor. ...

(MISSING_IT_THERE)

🔇 Additional comments (2)
docs/self-hosting/env/webapp.mdx (2)

81-92: Missing ARTIFACTS_OBJECT_STORE_* environment variables?

The env schema in apps/webapp/app/env.server.ts (lines 359-363) defines additional artifact-related object store variables that are not documented here:

  • ARTIFACTS_OBJECT_STORE_BUCKET
  • ARTIFACTS_OBJECT_STORE_BASE_URL
  • ARTIFACTS_OBJECT_STORE_ACCESS_KEY_ID
  • ARTIFACTS_OBJECT_STORE_SECRET_ACCESS_KEY
  • ARTIFACTS_OBJECT_STORE_REGION

Please verify if these should be documented for self-hosters, or if they're intentionally omitted (e.g., internal use only).


157-255: Well-structured migration documentation.

The Multi-Provider Object Storage section is thorough and accurately reflects the implementation:

  • Protocol prefix format matches parseStorageUri() regex
  • Environment variable naming pattern (OBJECT_STORE_{PROTOCOL}_*) aligns with getObjectStoreConfig()
  • Migration steps provide a clear zero-downtime path from R2 to S3

The use of <Steps> components and complete bash examples follows Mintlify best practices.

Comment on lines +113 to +114
| `MAXIMUM_DEV_QUEUE_SIZE` | No | — | Max dev queue size. |
| `MAXIMUM_DEPLOYED_QUEUE_SIZE` | No | — | Max deployed queue size. |
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Duplicate environment variable entries.

MAXIMUM_DEV_QUEUE_SIZE and MAXIMUM_DEPLOYED_QUEUE_SIZE appear twice in the table:

  • First at lines 113-114 under Limits
  • Again at lines 146-147 under Run engine

Remove one set to avoid confusion.

🐛 Proposed fix - remove duplicates from lines 146-147
 | `RUN_ENGINE_RATE_LIMIT_LIMITER_LOGS_ENABLED`     | No       | 0                     | Run engine rate limit limiter logs.                                                                                |
 | `RUN_ENGINE_DEFAULT_MAX_TTL`                     | No       | —                     | Maximum TTL for all runs (e.g. "14d"). Runs without a TTL use this as default; runs with a larger TTL are clamped. |
-| `MAXIMUM_DEV_QUEUE_SIZE`                         | No       | —                     | Maximum queued runs per queue in development environments.                                                         |
-| `MAXIMUM_DEPLOYED_QUEUE_SIZE`                    | No       | —                     | Maximum queued runs per queue in deployed (staging/prod) environments.                                             |
 | **Misc**                                         |          |                       |                                                                                                                    |

Also applies to: 146-147

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/self-hosting/env/webapp.mdx` around lines 113 - 114, The docs table
contains duplicate environment variable rows for MAXIMUM_DEV_QUEUE_SIZE and
MAXIMUM_DEPLOYED_QUEUE_SIZE; remove the second occurrences under the "Run
engine" section (the duplicate table rows referencing MAXIMUM_DEV_QUEUE_SIZE and
MAXIMUM_DEPLOYED_QUEUE_SIZE) so each environment variable appears only once in
the document and the tables remain consistent.

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.

1 participant