Skip to content

perf(database): index WorkerDeployment on (environmentId, status, id) for the deployments list - #4591

Merged
ericallam merged 1 commit into
mainfrom
feature/tri-13171-workerdeployment-list-pagination-scans-350x-rows-returned
Aug 12, 2026
Merged

perf(database): index WorkerDeployment on (environmentId, status, id) for the deployments list#4591
ericallam merged 1 commit into
mainfrom
feature/tri-13171-workerdeployment-list-pagination-scans-350x-rows-returned

Conversation

@ericallam

Copy link
Copy Markdown
Member

What

Adds a composite index @@index([environmentId, status, id]) to WorkerDeployment.

The public deployments list (GET /api/v1/deployments) filters by status and paginates by id descending. The existing indexes cover (environmentId, createdAt) and the PK, but nothing covers status. So for a status filter Postgres walks back through the environment's deployments discarding non-matching statuses, reading roughly 350 rows for every 1 returned (p99 ~1.1s on the busiest environments). The new index makes the status filter index-satisfied and lets id serve both the cursor range and the ORDER BY id DESC, bounding the read to a single page.

Full composite (not partial) because callers filter by arbitrary status values with no single dominant one.

Query

SELECT ... FROM "WorkerDeployment"
WHERE "environmentId" = $1 AND "status" = $2 [AND "id" < $3]
ORDER BY "id" DESC LIMIT $4;

Source: apps/webapp/app/routes/api.v1.deployments.ts.

Evidence

Reproduced on an isolated stack: one environment seeded with 7,000 deployments, the filtered status appearing 1 in 333 rows.

Before (no index):

Seq Scan on "WorkerDeployment"  (rows=21)
  Rows Removed by Filter: 6979
  Buffers: shared hit=206
Execution Time: 2.9 ms   (+ a sort for id desc)

After (with the index):

Index Scan Backward using "WorkerDeployment_environmentId_status_id_idx"
  Index Cond: (environmentId = $1 AND status = $2)
  Buffers: shared hit=23
Execution Time: 0.43 ms

Rows-removed-by-filter drops to 0; buffers 206 -> 23. The cursor (mid-pagination) variant uses the same index with all three predicates as the index condition. A dense/common status keeps the cheap PK backward scan (already fine); the index targets exactly the rare-status paths that were amplified.

End-to-end against the running webapp API: ?status=FAILED returns the correct newest-first page and paginates correctly across pages, and the emitted SQL matches the query above.

Rollout

  • Index only, CREATE INDEX CONCURRENTLY IF NOT EXISTS in its own migration file. Online-safe under write load.
  • Pre-apply the index in production before the migration deploys, per repo convention (the migration is then a no-op).
  • Rollback: drop the index. No data migration.

refs TRI-13171

… for the deployments list

The deployments list query filters by status and paginates by id desc, but no
index covered status, so Postgres seq-scanned the environment's deployments and
discarded ~350 non-matching rows per row returned. Add (environmentId, status,
id) so the status filter is index-satisfied and the scan is bounded to the page.
@changeset-bot

changeset-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 089d1e6

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

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 35fdeb29-e7be-4938-b477-b32af510cd8e

📥 Commits

Reviewing files that changed from the base of the PR and between 7b7d489 and 089d1e6.

📒 Files selected for processing (3)
  • .server-changes/worker-deployment-list-status-index.md
  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📜 Recent review details
⏰ Context from checks skipped due to timeout. (16)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (11, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (10, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (5, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (8, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (12, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (6, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (2, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (7, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (1, 12)
  • GitHub Check: webapp / 🧪 Unit Tests: Webapp (9, 12)
  • GitHub Check: runops-guard / runops-guard
  • GitHub Check: internal / 🧪 Unit Tests: Internal
  • GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp
  • GitHub Check: typecheck / typecheck
  • GitHub Check: code-quality / code-quality
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (2)
internal-packages/database/prisma/migrations/**/migration.sql

📄 CodeRabbit inference engine (internal-packages/database/CLAUDE.md)

internal-packages/database/prisma/migrations/**/migration.sql: When adding indexes to existing tables, use CREATE INDEX CONCURRENTLY IF NOT EXISTS to avoid production table locks.
Keep each CONCURRENTLY index in its own separate migration file, and add only one index per migration file.
Indexes on newly created tables may be created without CONCURRENTLY in the same migration as CREATE TABLE.
When adding an index for a new column on an existing table, use two migrations: first ALTER TABLE ... ADD COLUMN IF NOT EXISTS ..., then a separate migration containing CREATE INDEX CONCURRENTLY IF NOT EXISTS ....

Files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
internal-packages/database/prisma/schema.prisma

📄 CodeRabbit inference engine (internal-packages/database/CLAUDE.md)

internal-packages/database/prisma/schema.prisma: Define the database schema in prisma/schema.prisma using Prisma 6.14.0 for PostgreSQL.
New code must always target RunEngineVersion.V2; V1 is retired and retained only for historical rows and rejection.

Files:

  • internal-packages/database/prisma/schema.prisma
🧠 Learnings (17)
📓 Common learnings
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3368
File: internal-packages/database/prisma/schema.prisma:666-666
Timestamp: 2026-04-16T14:21:18.496Z
Learning: In `triggerdotdev/trigger.dev`, the `BackgroundWorkerTask` covering index on `(runtimeEnvironmentId, slug, triggerSource)` lives in `internal-packages/database/prisma/migrations/20260413000000_add_bwt_covering_index/migration.sql` as a `CREATE INDEX CONCURRENTLY IF NOT EXISTS`, intentionally in its own migration file separate from the `TaskIdentifier` table migration. Do not flag this index as missing from the schema migrations in future reviews.
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: internal-packages/database/prisma/migrations/20260318114244_add_prompt_friendly_id/migration.sql:5-5
Timestamp: 2026-03-22T13:49:23.474Z
Learning: In `internal-packages/database/prisma/migrations/**/*.sql`: When a column and its index are added in a follow-up migration file but the parent table itself was introduced in the same PR (i.e., no production rows exist yet), a plain `CREATE INDEX` / `CREATE UNIQUE INDEX` (without CONCURRENTLY) is safe and does not require splitting into a separate migration. The CONCURRENTLY requirement only applies when the table already has existing data in production.
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Pre-apply newly added indexes manually in production before deploying the migration; Prisma should skip creation when the index already exists.
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/migrations/**/migration.sql : When adding an index for a new column on an existing table, use two migrations: first `ALTER TABLE ... ADD COLUMN IF NOT EXISTS ...`, then a separate migration containing `CREATE INDEX CONCURRENTLY IF NOT EXISTS ...`.
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/migrations/**/migration.sql : Keep each `CONCURRENTLY` index in its own separate migration file, and add only one index per migration file.
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/migrations/**/migration.sql : When adding indexes to existing tables, use `CREATE INDEX CONCURRENTLY IF NOT EXISTS` to avoid production table locks.
📚 Learning: 2026-04-16T14:21:18.496Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3368
File: internal-packages/database/prisma/schema.prisma:666-666
Timestamp: 2026-04-16T14:21:18.496Z
Learning: In `triggerdotdev/trigger.dev`, the `BackgroundWorkerTask` covering index on `(runtimeEnvironmentId, slug, triggerSource)` lives in `internal-packages/database/prisma/migrations/20260413000000_add_bwt_covering_index/migration.sql` as a `CREATE INDEX CONCURRENTLY IF NOT EXISTS`, intentionally in its own migration file separate from the `TaskIdentifier` table migration. Do not flag this index as missing from the schema migrations in future reviews.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-03-22T13:49:20.068Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: internal-packages/database/prisma/migrations/20260318114244_add_prompt_friendly_id/migration.sql:5-5
Timestamp: 2026-03-22T13:49:20.068Z
Learning: For Prisma migration SQL files under `internal-packages/database/prisma/migrations/`, it is acceptable to create indexes with `CREATE INDEX` / `CREATE UNIQUE INDEX` (i.e., without `CONCURRENTLY`) when the parent table is introduced in the same PR and has no existing production rows yet. Only require `CREATE INDEX CONCURRENTLY` (or otherwise account for existing production data/locks) when the table already exists in production with data.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
📚 Learning: 2026-07-13T14:51:27.502Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/migrations/**/migration.sql : Indexes on newly created tables may be created without `CONCURRENTLY` in the same migration as `CREATE TABLE`.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-07-13T14:51:27.502Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/migrations/**/migration.sql : When adding an index for a new column on an existing table, use two migrations: first `ALTER TABLE ... ADD COLUMN IF NOT EXISTS ...`, then a separate migration containing `CREATE INDEX CONCURRENTLY IF NOT EXISTS ...`.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-07-13T14:51:27.502Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/migrations/**/migration.sql : When adding indexes to existing tables, use `CREATE INDEX CONCURRENTLY IF NOT EXISTS` to avoid production table locks.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-07-13T14:51:27.502Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/migrations/**/migration.sql : Keep each `CONCURRENTLY` index in its own separate migration file, and add only one index per migration file.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-02-03T18:48:31.790Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: internal-packages/database/prisma/migrations/20260129162810_add_integration_deployment/migration.sql:14-18
Timestamp: 2026-02-03T18:48:31.790Z
Learning: For Prisma migrations targeting PostgreSQL: - When adding indexes to existing tables, create the index in a separate migration file and include CONCURRENTLY to avoid locking the table. - For indexes on newly created tables (in CREATE TABLE statements), you can create the index in the same migration file without CONCURRENTLY. This reduces rollout complexity for new objects while protecting uptime for existing structures.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
📚 Learning: 2026-07-13T14:51:27.502Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Pre-apply newly added indexes manually in production before deploying the migration; Prisma should skip creation when the index already exists.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-07-13T14:51:27.502Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Applies to internal-packages/database/prisma/schema.prisma : Define the database schema in `prisma/schema.prisma` using Prisma 6.14.0 for PostgreSQL.

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-05-15T17:25:50.189Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/clickhouse/CLAUDE.md:0-0
Timestamp: 2026-05-15T17:25:50.189Z
Learning: Applies to internal-packages/clickhouse/schema/[0-9][0-9][0-9]_*.sql : DDL in migrations must be idempotent: use `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`, `CREATE TABLE IF NOT EXISTS`, `DROP TABLE IF EXISTS`, `ADD INDEX IF NOT EXISTS`, `DROP INDEX IF EXISTS`, and `CREATE MATERIALIZED VIEW IF NOT EXISTS` forms to allow out-of-order and retry-safe application

Applied to files:

  • internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql
📚 Learning: 2026-07-26T13:14:02.968Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 4378
File: .server-changes/realtime-run-reads-from-primary.md:0-0
Timestamp: 2026-07-26T13:14:02.968Z
Learning: For files in the .server-changes directory, the body text is published verbatim as dashboard-facing user release notes. Write entries in terms of user-visible behavior (what users can do/see), and avoid implementation-oriented details such as environment-variable names, internal mechanisms, or configuration knobs. If you need to include operational/configuration specifics, put those details in the PR description instead of the .server-changes entry.

Applied to files:

  • .server-changes/worker-deployment-list-status-index.md
📚 Learning: 2026-05-14T14:54:39.095Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3545
File: .server-changes/agent-view-sessions.md:10-10
Timestamp: 2026-05-14T14:54:39.095Z
Learning: In the `trigger.dev` repository, do not flag inconsistent dot vs slash notation in route/path strings inside `.server-changes/*.md` files. These markdown files are consumed verbatim into the changelog, so the mixed notation (e.g., `resources.orgs.../runs.$runParam/...`) is intentional and should be preserved as-is.

Applied to files:

  • .server-changes/worker-deployment-list-status-index.md
📚 Learning: 2026-03-22T13:49:23.474Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: internal-packages/database/prisma/migrations/20260318114244_add_prompt_friendly_id/migration.sql:5-5
Timestamp: 2026-03-22T13:49:23.474Z
Learning: In `internal-packages/database/prisma/migrations/**/*.sql`: When a column and its index are added in a follow-up migration file but the parent table itself was introduced in the same PR (i.e., no production rows exist yet), a plain `CREATE INDEX` / `CREATE UNIQUE INDEX` (without CONCURRENTLY) is safe and does not require splitting into a separate migration. The CONCURRENTLY requirement only applies when the table already has existing data in production.

Applied to files:

  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-07-13T14:51:27.502Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-07-13T14:51:27.502Z
Learning: Create migrations by editing `prisma/schema.prisma`, running `pnpm run db:migrate:dev:create --name "descriptive_name"` from `internal-packages/database`, cleaning up the listed extraneous generated migration objects and indexes, then running `pnpm run db:migrate:deploy && pnpm run generate`.

Applied to files:

  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-07-02T19:14:58.851Z
Learnt from: d-cs
Repo: triggerdotdev/trigger.dev PR: 4124
File: internal-packages/database/prisma/migrations/20260629120000_drop_run_ops_control_plane_foreign_keys/migration.sql:1-26
Timestamp: 2026-07-02T19:14:58.851Z
Learning: Repo triggerdotdev/trigger.dev: In the run-ops DB split (schema.prisma / internal-packages/database/prisma/migrations), the intentional pattern is to keep Prisma `relation` declarations on models like TaskRun, Waitpoint, TaskRunWaitpoint, TaskRunCheckpoint, TaskRunAttempt, TaskRunTag, and WaitpointTag even after dropping the corresponding DB-level foreign key constraints via migration (e.g., migrations under 20260629120000_drop_run_ops_control_plane_foreign_keys and related). This is not schema drift: on the dedicated run-ops DB, `internal-packages/run-store/src/PostgresRunStore.ts` uses `stripDedicatedRelations` to strip these relation keys from Prisma select/include before querying, then `#hydrateDedicatedRelations` re-populates them from scalar columns or join lookups (e.g., hydrateAssociatedWaitpoint, hydrateBlockingTaskRuns). Do not flag missing schema updates to remove `relation` fields when FK constraints are dropped in this codebase's run-ops split migrations.

Applied to files:

  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2026-04-30T21:28:35.705Z
Learnt from: samejr
Repo: triggerdotdev/trigger.dev PR: 3473
File: internal-packages/database/prisma/schema.prisma:59-60
Timestamp: 2026-04-30T21:28:35.705Z
Learning: When reviewing Prisma schema files in this repository, do not suggest using Prisma’s `@check` model/table-level attribute or any native Prisma schema syntax for CHECK constraints. Prisma does not implement CHECK constraints (see prisma/prisma#3388). If a CHECK constraint is required, add it only via raw SQL in a handwritten migration (e.g., `ALTER TABLE ... ADD CONSTRAINT ... CHECK (...)`).

Applied to files:

  • internal-packages/database/prisma/schema.prisma
🔇 Additional comments (3)
internal-packages/database/prisma/schema.prisma (1)

2217-2217: 🚀 Performance & Scalability

Verify that this index matches the target deployment-list query.

The supplied apps/webapp/app/presenters/v3/DeploymentListPresenter.server.ts query filters by projectId and environmentId, uses OFFSET, and orders by parsed version. It does not show a status predicate or an id cursor. If this presenter is the target path, validate the query with EXPLAIN (ANALYZE, BUFFERS) and either update the query or change the index to match the actual predicates and ordering. Otherwise, identify the status-and-cursor query served by this index.

internal-packages/database/prisma/migrations/20260812130000_add_worker_deployment_environment_id_status_id_index/migration.sql (1)

1-1: LGTM!

.server-changes/worker-deployment-list-status-index.md (1)

1-6: LGTM!


Walkthrough

Added a composite index on WorkerDeployment for environmentId, status, and id. Added a concurrent, idempotent migration to create the index. Added a changelog entry for faster status-filtered deployment-list loading.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the composite database index added for the deployments list performance improvement.
Description check ✅ Passed The description explains the change, query, performance evidence, testing, rollout, rollback, and issue reference, but omits the template checklist and screenshots.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tri-13171-workerdeployment-list-pagination-scans-350x-rows-returned

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.

@ericallam
ericallam marked this pull request as ready for review August 12, 2026 12:45

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@ericallam
ericallam merged commit 4658cd0 into main Aug 12, 2026
42 checks passed
@ericallam
ericallam deleted the feature/tri-13171-workerdeployment-list-pagination-scans-350x-rows-returned branch August 12, 2026 13:03
@github-actions github-actions Bot mentioned this pull request Aug 12, 2026
ericallam pushed a commit that referenced this pull request Aug 13, 2026
## Summary
4 new features, 24 improvements, 10 bug fixes.

## Highlights

- Allow `trigger deploy` to authenticate with an environment API key
from `TRIGGER_ACCESS_TOKEN`.
([#4561](#4561))

## Improvements
- Chat in the browser now reconnects when the connection drops mid-turn,
instead of leaving the reply stuck as if it were still generating.
Reports can be fetched as structured data with the `json` format, and
the shortest report period is now one minute (`1m`, `30m`, `1h`, `7d`).
The `mint-token` command's help is clearer too: a token minted without
`--cap` is read-only, and `--ttl` shows the correct maximum lifetime of
7 days.
([#4418](#4418))
- The dev environment onboarding now tracks real progress. After you run
`init`, the setup checklist marks your project as initialized, and it
updates live as your dev server connects and your tasks register. The
blank state also adds a "Copy AI agent prompt" button that copies a
ready-to-paste setup prompt (pre-filled with your project reference) for
Claude Code, Cursor, or any coding agent.
([#4563](#4563))
  
The `init` scaffold now imports from `@trigger.dev/sdk` instead of the
deprecated `@trigger.dev/sdk/v3` subpath.
- Deployed images now ship dependencies and bundled task code as
separate layers. Repeat deploys with unchanged dependencies typically
push and pull far less data, making deploys and worker image pulls
faster.
([#4551](#4551))
- The current-worker API now reports each task's queue, so you can see
which tasks write to a given queue.
([#4525](#4525))
- Watch-mode chat streams now survive quiet windows and page reloads,
and a reply cut off by a lost connection shows an error instead of
appearing finished. Aborting a resumed subscription only closes your
local stream — call `stopGeneration(chatId)` or pass `stopOnAbort: true`
to stop the run. Also fixed a race where quickly restarting a stream
could break stop and reconnect, and stopping a chat now hands it back to
your other tabs instead of leaving them read-only.
([#4516](#4516))

## Server changes

These changes affect the self-hosted Docker image and Trigger.dev Cloud:

- The dashboard agent now has a monthly message allowance and plan-based
limits on watches. Queries stay read-only with clearer errors when busy,
and messages with unusual characters no longer fail to send.
([#4516](#4516))
- Meet the dashboard agent: a chat in every environment that answers
questions about your runs, queues, errors and health with real data and
links, replacing Ask AI everywhere it used to appear. Investigate a
failed run, an error, a backed-up queue or a run that hasn't started to
get a worked-through answer — what happened, why, and how to fix it,
with every claim linked to the runs, errors and deploys behind it. It
reads your data read-only, works on preview and dev branches with that
branch's own data, and reads the same everywhere — dashboard, terminal,
editor. A very long chat keeps working: the agent summarises the earlier
part and carries on.
  
**Watch…** on a run, queue, error or the health report tells you when
things change: a run finishes, a queue clears or grows past a number you
pick, an error comes back, an environment recovers. The answer arrives
in the chat and, if you want, by email, Slack or webhook — and the agent
can look into bad news on its own. A watch reaches you on any browser
you sign in from, without opening the chat first.
  
A sample of conversations is scored automatically so the agent keeps
getting better; only the score and a one-line summary are kept, never
your messages, data or code, and we can switch it off for your
organization on request. Ask the agent instead of the Docs buttons in
page headers — they stay there when the agent isn't available to you.
Separately, a queue's wait times, peak depth, throughput and throttling
can now be read from the API.
([#4418](#4418))
- Add backend support for delaying cron schedules within a specified
window with a minimum of 60 seconds.
([#4566](#4566))
- Reduced recurring background database load from the billing-limit
recovery check, so paused environments are reconciled with less
overhead.
([#4590](#4590))
- Validating a schedule when deploying or updating a schedule now does
less work on projects with many preview branches, so those operations
stay fast as branches accumulate.
([#4598](#4598))
- Project pages now load faster for projects with a large number of
preview branches, by no longer loading archived branch environments that
aren't shown.
([#4595](#4595))
- Database queries that filter on a list of values now reuse cached
query plans more consistently, instead of forcing the database to
re-plan whenever the list length changes.
([#4480](#4480))
- Routine cleanup of old dashboard agent data now runs on its own
schedule.
([#4599](#4599))
- Database connection metrics are now reported for every configured
database connection instead of only the primary one, and stay accurate
regardless of connection type.
([#4541](#4541))
- Deployment-related API endpoints now draw from their own generous rate
limit budget, configurable via the `DEPLOYMENT_RATE_LIMIT_*` environment
variables, so runtime API traffic no longer competes with deployments
for the same per-environment budget.
([#4565](#4565))
- Deleting or editing a secret environment variable is now fast and no
longer slows down as a project accumulates variables.
([#4555](#4555))
- Speed up personal access token lookups by indexing them on their owner
([#4588](#4588))
- Switching project or organization in the sidebar now keeps you on the
same page instead of sending you back to Tasks. Pages for a specific
run, deploy or other single item open the matching list instead.
([#4585](#4585))
- Reduced database load when loading the dashboard by removing an unused
organization member count that was being calculated on every page
navigation.
([#4587](#4587))
- The environment variables page now loads a page at a time, keeping it
fast for projects with a large number of variables. Search matches
variable names across every page.
([#4597](#4597))
- Groundwork for an alternative database connection driver, gated behind
configuration and disabled by default, so there is no change to default
behavior.
([#4539](#4539))
- Deleting an alert channel is now fast and no longer slows down as a
project builds up alert history.
([#4554](#4554))
- Reduced internal overhead on the API under high load.
([#4532](#4532))
- Out-of-date upgrade prompts no longer appear in the dashboard: the
"V4" badges and the notices saying preview branches and the queues table
need V4 have been removed. The side menu still warns you when a project
is on v3, with updated wording and a link to the v4 upgrade guide.
([#4589](#4589))
- Make background worker registration cheaper for projects with many
scheduled tasks by scoping declarative schedule reconciliation to the
current environment and dropping redundant schedule lookups.
([#4577](#4577))
- Speed up setting and importing environment variables for projects with
many variables.
([#4579](#4579))
- Loading the deployments list is now faster, especially when filtering
by deployment status on projects with many deployments.
([#4591](#4591))
- Fixed the billing limits page timing out for organizations with many
preview branches, especially while a spend limit was being enforced. The
page now loads quickly, so you can raise or resolve your limit without
delay. ([#4594](#4594))
- Fix the Concurrency page showing the plan's default concurrency for
the dev environment instead of the environment's actual limit.
([#4596](#4596))
- Creating an organization sometimes left you back on the creation form
even though the organization had already been created, so clicking
Create again made a duplicate. Creating an organization now completes
and takes you to your new organization.
([#4530](#4530))
- Ensure creating a project completes instead of returning to its
creation form after a navigation error.
([#4584](#4584))
- Renaming a project now keeps you on the project settings page and
tells you what happened, instead of silently moving you to the tasks
page or clearing the form with no explanation.
([#4601](#4601))
- Fixed support threads showing no account details for some customers,
so the team can see your plan, organizations and projects when you get
in touch.
([#4575](#4575))
- In the light theme, the Format, Clear and Copy buttons on the query
editor no longer blend into the query text behind them.
([#4592](#4592))
- The health report now says start latency is "unknown" when there is no
data for it, instead of showing a healthy-looking 0ms
([#4544](#4544))
- Realtime streams written inside a chat session run now use the same
backend as the session itself, and runs are no longer created against a
backend that cannot serve them.
([#4564](#4564))
- The grouped "watch updates" notification now shows the total number of
results waiting, instead of only the most recent batch's count.
([#4525](#4525))

<details>
<summary>Raw changeset output</summary>

# Releases
## @trigger.dev/build@4.5.11

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.11`
## trigger.dev@4.5.11

### Patch Changes

- Chat in the browser now reconnects when the connection drops mid-turn,
instead of leaving the reply stuck as if it were still generating.
Reports can be fetched as structured data with the `json` format, and
the shortest report period is now one minute (`1m`, `30m`, `1h`, `7d`).
The `mint-token` command's help is clearer too: a token minted without
`--cap` is read-only, and `--ttl` shows the correct maximum lifetime of
7 days.
([#4418](#4418))
- Allow `trigger deploy` to authenticate with an environment API key
from `TRIGGER_ACCESS_TOKEN`.
([#4561](#4561))
- The dev environment onboarding now tracks real progress. After you run
`init`, the setup checklist marks your project as initialized, and it
updates live as your dev server connects and your tasks register. The
blank state also adds a "Copy AI agent prompt" button that copies a
ready-to-paste setup prompt (pre-filled with your project reference) for
Claude Code, Cursor, or any coding agent.
([#4563](#4563))

The `init` scaffold now imports from `@trigger.dev/sdk` instead of the
deprecated `@trigger.dev/sdk/v3` subpath.

- Deployed images now ship dependencies and bundled task code as
separate layers. Repeat deploys with unchanged dependencies typically
push and pull far less data, making deploys and worker image pulls
faster.
([#4551](#4551))
- Updated dependencies:
  - `@trigger.dev/core@4.5.11`
  - `@trigger.dev/build@4.5.11`
  - `@trigger.dev/schema-to-json@4.5.11`
## @trigger.dev/core@4.5.11

### Patch Changes

- Chat in the browser now reconnects when the connection drops mid-turn,
instead of leaving the reply stuck as if it were still generating.
Reports can be fetched as structured data with the `json` format, and
the shortest report period is now one minute (`1m`, `30m`, `1h`, `7d`).
The `mint-token` command's help is clearer too: a token minted without
`--cap` is read-only, and `--ttl` shows the correct maximum lifetime of
7 days.
([#4418](#4418))
- The current-worker API now reports each task's queue, so you can see
which tasks write to a given queue.
([#4525](#4525))
## @trigger.dev/python@4.5.11

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.11`
  - `@trigger.dev/sdk@4.5.11`
  - `@trigger.dev/build@4.5.11`
## @trigger.dev/react-hooks@4.5.11

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.11`
## @trigger.dev/redis-worker@4.5.11

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.11`
## @trigger.dev/rsc@4.5.11

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.11`
## @trigger.dev/schema-to-json@4.5.11

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.11`
## @trigger.dev/sdk@4.5.11

### Patch Changes

- Chat in the browser now reconnects when the connection drops mid-turn,
instead of leaving the reply stuck as if it were still generating.
Reports can be fetched as structured data with the `json` format, and
the shortest report period is now one minute (`1m`, `30m`, `1h`, `7d`).
The `mint-token` command's help is clearer too: a token minted without
`--cap` is read-only, and `--ttl` shows the correct maximum lifetime of
7 days.
([#4418](#4418))
- Watch-mode chat streams now survive quiet windows and page reloads,
and a reply cut off by a lost connection shows an error instead of
appearing finished. Aborting a resumed subscription only closes your
local stream — call `stopGeneration(chatId)` or pass `stopOnAbort: true`
to stop the run. Also fixed a race where quickly restarting a stream
could break stop and reconnect, and stopping a chat now hands it back to
your other tabs instead of leaving them read-only.
([#4516](#4516))
- Updated dependencies:
  - `@trigger.dev/core@4.5.11`

</details>

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants