Trigger.dev Release Notes
200 release notes curated from 60 sources by the Releasebot Team. Last updated: Aug 29, 2026
- Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
Trigger.dev v4.5.14
Trigger.dev adds realtime stream upgrades, including from: latest starts, cursor resumption, a new useSessionStream hook, and token refresh for long-running subscriptions. It also improves native build server logs and fixes queue retries in the server.
Highlights
Realtime stream improvements: from: "latest", cursor resumption, and useSessionStream
Realtime stream improvements: from: "latest", cursor resumption, and useSessionStream get three new capabilities in this release.
Start at the current tail. Pass from: "latest" to useRealtimeStream, streams.read(), or fetchStream to skip history and only receive live updates from the point you connect. Pair it with maxParts to keep the accumulated parts array bounded, which is useful for "last value" views like a live progress indicator.
Resume from a saved cursor. useRealtimeStream now accepts a lastEventId option and returns lastEventId in its result, so you can persist the position across page reloads and resume exactly where you left off. An onParts callback delivers each throttled batch alongside their event IDs. A reconnect or remount resumes from the last record seen, so no records are missed or replayed.
New useSessionStream hook. Read a chat agent Session's realtime channel from React without hand-rolling the API client, record accumulation, unmount cleanup, throttling, or cursor tracking. Because a Session is durable and can span multiple runs, the channel it reads outlives any single run and supports multiple concurrent subscribers, which makes it the natural way to render a chat.agent session's output as it streams.
Pass io: "out" (the default) to read the agent's output channel, or io: "in" to read its input. It takes the same subscription controls as the run-stream hooks, from: "latest", maxRecords, and lastEventId, plus an onRecords callback that delivers each throttled batch of records with their event ids and an onControl callback for control records like turn-complete (control records never enter the records array). It returns { records, lastEventId, lastControl, error, stop }.
Where useRealtimeStream reads a single run's stream, useSessionStream reads a Session's channel, so it keeps streaming across the runs that make up a conversation. It reads only, and requires a Public Access Token scoped read:sessions:{id}. (#4811)
Token refresh. A Public Access Token is short-lived (15 minutes by default), so a realtime subscription that watches a long-running run or a session stream can outlive its token. Until now that surfaced as an auth error with no recovery short of tearing the subscription down and creating a new one. The new refreshAccessToken option lets a subscription mint a fresh token and reconnect on its own.
It's an async callback that resolves to a fresh token, typically fetched from your backend where your secret key lives:
Set it on any realtime subscription (run streams, realtime runs, and session streams), or once on TriggerAuthContext.Provider so every hook underneath shares one refresher:
The refresh is reactive: when a connection is rejected with an auth error, the subscription calls refreshAccessToken once, retries with the new token, and resumes from its last-seen record, so there is no gap and no replay. It is bounded to one refresh per connection so a rejected token can't drive a retry loop, and hooks that share a refresher dedupe a single in-flight mint. It is fully opt-in: with no refreshAccessToken supplied, auth errors stay terminal exactly as before. (#4811)
Improvements
• Native build server deploys now show a single updating log line by default. Pass --build-logs full to stream every line, which is always the behavior in CI and when output is not a terminal. (#4817)
Server changes
These changes are included in the v4.5.14 Docker image and are already live on Trigger.dev Cloud:
• Task retries that wait in the queue no longer count against the queue's internal redelivery limit, fixing runs with many long-delay retries being wrongly failed with TASK_RUN_DEQUEUED_MAX_RETRIES. (#4810)
How to upgrade
Update the trigger.dev/* packages to v4.5.14 using your package manager:
npx trigger.dev@latest update # npm pnpm dlx trigger.dev@latest update # pnpm yarn dlx trigger.dev@latest update # yarn bunx trigger.dev@latest update # bunSelf-hosted users: update your Docker image to ghcr.io/triggerdotdev/trigger.dev:v4.5.14.
Original source - Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
Trigger.dev v4.5.13
Trigger.dev releases stronger chat agent reliability and new custom agent building blocks, including pending message handling, handoff to fresh runs, and client data validation. It also adds deployment and dashboard improvements, plus performance boosts and bug fixes across chat, logs, and runs lists.
6 improvements, 4 bug fixes, and 10 server changes
Highlights
More reliable chat agents
This release hardens chat agent message delivery from end to end. A message that arrives while an agent is mid-turn is no longer dropped, a recovered answer after a crash is no longer cut off, and a message left outstanding when a run is killed is now re-answered on the next run. Together these close the cases where a chat could silently lose a message or leave a turn stuck.
Custom agents also get new building blocks.
chat.messages.hasPending()andchat.messages.next()let a hand-rolled loop inspect pending input without consuming it and take one record at a time:if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }chat.endAndContinue()hands a conversation off to a fresh run on the latest deployed task version while preserving unconsumed session input, andchat.withClientData({ schema })now validates and parses client data before it reaches agent code.Improvements
- A message that arrives mid-turn and isn't injected into the current turn is now answered as the next turn instead of being dropped. Previously, configuring pendingMessages without a shouldInject declined every batch, so every mid-turn message was silently lost. A declined message keeps its place in the queue and survives a crash; an injected one is consumed at injection and never also answered as a later turn. (#4795)
- Browser chats now keep the active turn open across page reloads when older completion records are replayed. (#4643)
- Added
chat.endAndContinue()so fully hand-rolled custom chat agents can hand a conversation off to a fresh run on the latest deployed task version while preserving unconsumed session input. (#4647) - Custom chat agents now validate and parse client data declared with
chat.withClientData({ schema })before passing it to agent code. (#4646) - Added an experimental
--local-bundledeploy flag that runs the install and bundling steps on your machine and uploads only the build output; the image is still built remotely. Useful when your project's install step needs tooling or credentials that only exist locally. (#4331) trigger.dev deploynow asks the server whether to build with Depot or the native build server, unless--native-build,--depot-build, or--local-buildis explicitly passed.--local-bundleand--detachnow require--native-build. (#4803)
Bug fixes
- Fixed several chat message reliability issues: a message arriving mid-turn could be silently lost if the run crashed; a recovered answer after a crash could be cut off because the stop that arrived during the turn was replayed into the recovery run; a retried send could be answered twice when its idempotency claim was lost. Custom agent loops can now inspect pending input without consuming it using
chat.messages.hasPending()and consume one record at a time withchat.messages.next(). (#4644) - Fixed a chat agent hanging after an interrupted turn: when a run was killed mid-answer and only the one message it was answering was still outstanding, the new run never replied to it. (#4768)
- Fixed chat transport discarding the next turn after stopping generation.
skipToTurnCompleteis now reset when a new message or action is sent, so a message sent afterstopGenerationstreams normally instead of leaving the chat stuck in a streaming state. (#4744) - Fixed a message sent while the agent was mid-answer being lost if the run then crashed. The cursor written at the end of each turn now holds back behind any message still waiting to be handled. The in-memory buffer for pending mid-turn messages has been removed from both
chat.agentandchat.createSession()so waiting messages are durable. (#4795)
Server changes
These changes are included in the v4.5.13 Docker image and are already live on Trigger.dev Cloud:
- Self-hosted instances can now disable the admin dashboard and user impersonation entirely via a new setting. (#4774)
- The dashboard has two new themes, Black and White, plus appearance options for stronger colors and underlined links. (#4547)
- Deployment logs no longer jump to the bottom while you are reading earlier output. Scroll up to pause auto-scroll; scroll back down or use the new scroll-to-bottom button in the log header to resume. (#4776)
- Customize the runs list: show, hide, and reorder columns, and add smart columns that pull a value out of a run's payload, metadata, or output. Column choices are saved in the page URL so you can share or bookmark a view. (#4652)
- The browser no longer offers to autofill or save environment variable values as saved credentials. (#4777)
- Cut webapp CPU usage by about a quarter on the routes workers call most. Detailed event-loop blocking traces are no longer recorded by default, as producing them was a significant part of that cost. (#4746)
- Runs list and runs.list API requests that span too much data now return a clear error asking you to narrow the time range, instead of failing with a generic error. (#4773)
- Improved performance and reliability of the runs list and runs.list API, especially for large projects and filtered views. (#4763)
- New Vercel connections now get version skew protection turned on automatically, so each run uses the task version its deployment shipped with. Automatic atomic deployments are deprecated and no longer offered when connecting a project, but remain available in your Vercel integration settings. (#4741)
- The Staging branch setting now shows a correct status when it's not available in the current configuration, instead of appearing editable and silently doing nothing on save. (#4784)
How to upgrade
Update the trigger.dev/* packages to v4.5.13 using your package manager:
npx trigger.dev@latest update # npm pnpm dlx trigger.dev@latest update # pnpm yarn dlx trigger.dev@latest update # yarn bunx trigger.dev@latest update # bunSelf-hosted users: update your Docker image to ghcr.io/triggerdotdev/trigger.dev:v4.5.13.
Original source All of your release notes in one feed
Join Releasebot and get updates from Trigger.dev and hundreds of other software products.
- Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
trigger.dev v4.5.14
Trigger.dev releases v4.5.14 with clearer native build server logs, more resilient realtime streams that can refresh tokens and resume from the latest record, plus a new useSessionStream React hook and a fix for queued retries hitting redelivery limits.
trigger.dev v4.5.14
Upgrade
npx trigger.dev@latest update # npm
pnpm dlx trigger.dev@latest update # pnpm
yarn dlx trigger.dev@latest update # yarn
bunx trigger.dev@latest update # bun
Self-hosted Docker image: ghcr.io/triggerdotdev/trigger.dev:v4.5.14
Release notes
Read the full release notes: https://trigger.dev/changelog/v4-5-14
What's changed
Improvements
Native build server deploys now show a single updating build log line by default; pass --build-logs full to stream every line (always used in CI and when output is not a terminal). (#4817)
Realtime stream subscriptions can now refresh an expired access token and reconnect, via a new optional refreshAccessToken option on the client configuration and the React hooks. (#4811)
Subscribe to a realtime stream from its latest record instead of replaying the whole history. Pass from: "latest" to useRealtimeStream, streams.read(), or fetchStream to start at the current tail (the latest record, then live updates) instead of replaying (a live "last value" view), and maxParts to keep the accumulated parts array bounded. A reconnect or remount resumes from the last record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall back to a full replay. (#4811)
useRealtimeStream also gains a lastEventId option and returns the lastEventId of the last part seen, so you can persist the cursor (for example across a page reload) and resume exactly where you left off. An onParts callback delivers each throttled batch of parts with their event ids.
const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });Added a useSessionStream React hook for reading a session's output or input channel in realtime. It accumulates records with automatic resume from the last record you received, and supports from: "latest" (start at the current tail, only new records after you connect), maxRecords (keep a bounded number of records in memory), a lastEventId resume cursor, and an onRecords callback that delivers each throttled batch of records with their event ids. (#4811)
Server changes
These changes affect the self-hosted Docker image and Trigger.dev Cloud:
Task retries that wait in the queue no longer count against the queue's internal redelivery limit, so runs with many long-delay retries are not wrongly failed with TASK_RUN_DEQUEUED_MAX_RETRIES. (#4810)
All packages: v4.5.14
@trigger.dev/build, @trigger.dev/core, @trigger.dev/python, @trigger.dev/react-hooks, @trigger.dev/redis-worker, @trigger.dev/rsc, @trigger.dev/schema-to-json, @trigger.dev/sdk, trigger.dev
Contributors
Saadi Myftija, James Ritchie, @d-cs, github-actions[bot], Matt Aitken, @nicktrn, Chris Arderne, Eric Allam
Full changelog: v4.5.13...v4.5.14
Original source - Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
trigger.dev v4.5.13
Trigger.dev ships v4.5.13 with smarter deploys, a new experimental local-bundle flag, and major chat reliability fixes that preserve mid-turn messages across crashes. It also adds dashboard themes, customizable run lists, and performance and self-hosting improvements.
Upgrade
npx trigger.dev@latest update # npm pnpm dlx trigger.dev@latest update # pnpm yarn dlx trigger.dev@latest update # yarn bunx trigger.dev@latest update # bunSelf-hosted Docker image: ghcr.io/triggerdotdev/trigger.dev:v4.5.13
Release notes
Read the full release notes: https://trigger.dev/changelog/v4-5-13
What's changed
Improvements
trigger.dev deploy now asks the server whether to build with Depot or the native build server unless --native-build, --depot-build, or --local-build is passed, so the native build server can be rolled out per organization without a CLI change. --local-bundle and --detach now require --native-build. (#4803)
Add an experimental --local-bundle deploy flag that runs the install and bundling steps on your machine and uploads only the build output; the image is still built remotely. Useful when your project's install step needs tooling or credentials that only exist locally. (#4331)
Send the CLI version header on all API requests so deployments are attributable to a CLI version (#4778)
A message that arrives mid-turn and is not injected into that turn is now answered as the next turn, instead of being dropped. This is what the pendingMessages docs have always described, and it applies to the default too: configuring pendingMessages without a shouldInject declines every batch, which previously meant every mid-turn message was lost with no error at either end. (#4795)
chat.agent({ id: "my-chat", pendingMessages: { onReceived: ({ message }) => logger.info("arrived mid-turn", { id: message.id }), // Only interrupt once the agent has started calling tools. shouldInject: ({ steps }) => steps.length > 0, }, run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal, // Required for injection. Without it nothing injects, and every // mid-turn message is answered as the next turn instead. ...chat.toStreamTextOptions(), }), });A declined message keeps its place in the queue, so it survives a crash and is answered by whichever run picks the conversation up. An injected one is consumed at the moment it is injected, so it is never also answered as a later turn.
Browser chats now keep the active turn open across page reloads when older completion records are replayed. (#4643)
Add chat.endAndContinue() so fully hand-rolled custom chat agents can hand a conversation off to a fresh run on the latest deployed task version while preserving unconsumed Session input. (#4647)
Custom chat agents now validate and parse client data declared with chat.withClientData({ schema }) before passing it to agent code. (#4646)
Bug fixes
Fixes a case where a chat could silently lose a message. If a message arrived while the agent was between turns and a stop arrived after it, the cursor the next boot resumed from could point past that message, so it was never answered and no error was raised. This affected chat.agent, not just custom agents. (#4644)
Fixes a recovered answer being cut off. After a crash the agent replays the message it had not answered yet, but it was replaying the stop that arrived after that message too, so the turn answering it was aborted the moment it began. A stop is now only applied to the turn that was live when it arrived. That holds however the stop got there: sent after the last completed turn, or sent to a chat whose most recent turn was completed by an older version of the SDK.
One limitation to know about: the recovered answer is persisted correctly, but a chat page that stayed open across the crash keeps showing the partial answer it had already received. Reload the page to see the full recovered answer.
Also fixes a retried send being answered twice. When a send was retried and its idempotency claim was lost, the agent could consume the same message a second time.
Custom agent loops can now inspect pending chat input without consuming it, and consume one record at a time, with chat.messages.hasPending() and chat.messages.next(). Records carry stable identifiers so a redelivery is recognisable.
if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }hasPending() answers for messages alone, so a message sitting behind a stop, or behind a record this version of the SDK does not recognise, still reports as pending and is still delivered. Anything the agent has no consumer for is discarded rather than left where it would make every message queued behind it undeliverable. chat.messages.next() returning undefined means no message became consumable before the timeout.
chat.writeTurnComplete()'s sessionInEventId is the cursor that is safe to resume from, not the sequence of the record the turn answered. It is held back behind any message still waiting to be handled, so a value below the record you just handled is expected.
Fixed a chat agent hanging after an interrupted turn: when a run was killed mid-answer (out of memory, crash, or eviction) and only the one message it was answering was still outstanding, the new run never replied to it. That message is now re-answered on the new run. (#4768)
Fix chat transport discarding the next turn after stopping generation. skipToTurnComplete is now reset when a new message or action is sent, so a message sent after stopGeneration streams normally instead of leaving the chat stuck in a streaming state. (#4744)
Fixes a message sent while the agent was mid-answer being lost if the run then crashed. The cursor written at the end of each turn could point past a message that had arrived during that turn but had not been answered yet, so the next boot skipped it and no error was raised anywhere. Such a message is now held until a turn actually takes it. (#4795)
This also removes the in-memory buffer those messages used to sit in, on both chat.agent and chat.createSession(), so a message waiting for its turn is durable rather than only present in the worker that received it.
Server changes
These changes affect the self-hosted Docker image and Trigger.dev Cloud:
Self-hosted instances can now disable the admin dashboard and user impersonation entirely. See the self-hosting docs for the new setting. (#4774)
The dashboard has two new themes, Black and White, plus appearance options for stronger colors and underlined links. (#4547)
Deployment logs no longer jump to the bottom while you are reading earlier output. Scroll up to pause auto-scroll, and scroll back down or use the new scroll-to-bottom button in the log header to resume following. (#4776)
Customize the runs list: show, hide, and reorder columns, and add smart columns that pull a value straight out of a run's payload, metadata, or output. Your column choices are saved in the page URL, so you can share a view, bookmark it, or save it straight to your favorites. (#4652)
Stop the browser offering to autofill or save environment variable values as saved credentials. (#4777)
Cut webapp CPU usage by about a quarter on the routes that workers call most, freeing headroom at the same request rate. Detailed event-loop blocking traces are no longer recorded by default, because producing them was itself a large part of that cost. (#4746)
When a runs list or runs.list API request spans too much data to complete, it now returns a clear, actionable error asking you to narrow the time range, instead of failing with a generic error. (#4773)
Improved the performance and reliability of the runs list and the runs.list API, especially for large projects and filtered views. (#4763)
New Vercel connections now get version skew protection turned on automatically, so each run uses the task version its deployment shipped with. Automatic atomic deployments are deprecated and no longer offered when you connect a project, but stay available in your Vercel integration settings. (#4741)
The Staging branch setting now shows an upgrade prompt on plans that don't include a Staging environment, instead of looking editable and then silently doing nothing when saved. (#4784)
All packages: v4.5.13
@trigger.dev/build, @trigger.dev/core, @trigger.dev/python, @trigger.dev/react-hooks, @trigger.dev/redis-worker, @trigger.dev/rsc, @trigger.dev/schema-to-json, @trigger.dev/sdk, trigger.dev
Contributors
@d-cs, Eric Allam, Saadi Myftija, Graham Tremper, Oskar Otwinowski, @nicktrn, claude[bot], @D-K-P, github-actions[bot], @wei-wei, James Ritchie, Chris Arderne
Full changelog: v4.5.12...v4.5.13
Original source - Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
v.docker.4.5.14: chore: release v4.5.14 (#4813)
Trigger.dev adds smarter realtime streaming and more reliable deployments, with resumable stream subscriptions, latest-record access, session stream hooks, refreshed access tokens, bounded record history, and cleaner native build logs. It also fixes queue retries so delayed tasks are not wrongly failed.
Summary
4 improvements, 1 bug fix.
Improvements
Native build server deploys now show a single updating build log line by default; pass --build-logs full to stream every line (always used in CI and when output is not a terminal).
(#4817)
Realtime stream subscriptions can now refresh an expired access token and reconnect, via a new optional refreshAccessToken option on the client configuration and the React hooks.
(#4811)
Subscribe to a realtime stream from its latest record instead of replaying the whole history. Pass from: "latest" to useRealtimeStream, streams.read(), or fetchStream to start at the current tail (the latest record, then live updates) instead of replaying (a live "last value" view), and maxParts to keep the accumulated parts array bounded. A reconnect or remount resumes from the last record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall back to a full replay.
(#4811)
useRealtimeStream also gains a lastEventId option and returns the lastEventId of the last part seen, so you can persist the cursor (for example across a page reload) and resume exactly where you left off. An onParts callback delivers each throttled batch of parts with their event ids.
const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });Added a useSessionStream React hook for reading a session's output or input channel in realtime. It accumulates records with automatic resume from the last record you received, and supports from: "latest" (start at the current tail, only new records after you connect), maxRecords (keep a bounded number of records in memory), a lastEventId resume cursor, and an onRecords callback that delivers each throttled batch of records with their event ids.
(#4811)
Server changes
These changes affect the self-hosted Docker image and Trigger.dev Cloud:
Task retries that wait in the queue no longer count against the queue's internal redelivery limit, so runs with many long-delay retries are not wrongly failed with TASK_RUN_DEQUEUED_MAX_RETRIES.
(#4810)
Raw changeset output
Releases
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
Patch Changes
Native build server deploys now show a single updating build log line by default; pass --build-logs full to stream every line (always used in CI and when output is not a terminal).
(#4817)
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Realtime stream subscriptions can now refresh an expired access token and reconnect, via a new optional refreshAccessToken option on the client configuration and the React hooks.
(#4811)
Subscribe to a realtime stream from its latest record instead of replaying the whole history. Pass from: "latest" to useRealtimeStream, streams.read(), or fetchStream to start at the current tail (the latest record, then live updates) instead of replaying (a live "last value" view), and maxParts to keep the accumulated parts array bounded. A reconnect or remount resumes from the last record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall back to a full replay.
(#4811)
useRealtimeStream also gains a lastEventId option and returns the lastEventId of the last part seen, so you can persist the cursor (for example across a page reload) and resume exactly where you left off. An onParts callback delivers each throttled batch of parts with their event ids.
const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Realtime stream subscriptions can now refresh an expired access token and reconnect, via a new optional refreshAccessToken option on the client configuration and the React hooks.
(#4811)
Subscribe to a realtime stream from its latest record instead of replaying the whole history. Pass from: "latest" to useRealtimeStream, streams.read(), or fetchStream to start at the current tail (the latest record, then live updates) instead of replaying (a live "last value" view), and maxParts to keep the accumulated parts array bounded. A reconnect or remount resumes from the last record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall back to a full replay.
(#4811)
useRealtimeStream also gains a lastEventId option and returns the lastEventId of the last part seen, so you can persist the cursor (for example across a page reload) and resume exactly where you left off. An onParts callback delivers each throttled batch of parts with their event ids.
const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });Added a useSessionStream React hook for reading a session's output or input channel in realtime. It accumulates records with automatic resume from the last record you received, and supports from: "latest" (start at the current tail, only new records after you connect), maxRecords (keep a bounded number of records in memory), a lastEventId resume cursor, and an onRecords callback that delivers each throttled batch of records with their event ids.
(#4811)
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Subscribe to a realtime stream from its latest record instead of replaying the whole history. Pass from: "latest" to useRealtimeStream, streams.read(), or fetchStream to start at the current tail (the latest record, then live updates) instead of replaying (a live "last value" view), and maxParts to keep the accumulated parts array bounded. A reconnect or remount resumes from the last record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall back to a full replay.
(#4811)
useRealtimeStream also gains a lastEventId option and returns the lastEventId of the last part seen, so you can persist the cursor (for example across a page reload) and resume exactly where you left off. An onParts callback delivers each throttled batch of parts with their event ids.
const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });Updated dependencies:
@trigger.dev/[email protected]
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Original source Similar to Trigger.dev with recent updates:
- Okta release notes109 release notes · Latest Aug 27, 2026
- Anthropic release notes789 release notes · Latest Aug 28, 2026
- Zed release notes164 release notes · Latest Aug 26, 2026
- Supabase release notes103 release notes · Latest Aug 21, 2026
- Obsidian release notes107 release notes · Latest Aug 20, 2026
- Perplexity release notes30 release notes · Latest Aug 24, 2026
- Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
v.docker.4.5.13: chore: release v4.5.13 (#4769)
Trigger.dev adds a major release with smarter deploy builds, new local bundle options, and stronger chat agent handling. It also improves runs list performance, dashboard themes and controls, and fixes several message delivery and recovery bugs for more reliable chats.
Summary
4 new features, 12 improvements, 5 bug fixes.
Improvements
trigger.dev deploy now asks the server whether to build with Depot
or the native build server unless --native-build, --depot-build, or
--local-build is passed, so the native build server can be rolled out
per organization without a CLI change. --local-bundle and --detach
now require --native-build.(#4803)
Add an experimental --local-bundle deploy flag that runs the install
and bundling steps on your machine and uploads only the build output;
the image is still built remotely. Useful when your project's install
step needs tooling or credentials that only exist locally.(#4331)
Send the CLI version header on all API requests so deployments are
attributable to a CLI version(#4778)
A message that arrives mid-turn and is not injected into that turn is
now answered as the next turn, instead of being dropped. This is what
the pendingMessages docs have always described, and it applies to the
default too: configuring pendingMessages without a shouldInject
declines every batch, which previously meant every mid-turn message was
lost with no error at either end.(#4795)
chat.agent({ id: "my-chat", pendingMessages: { onReceived: ({ message }) => logger.info("arrived mid-turn", { id: message.id }), // Only interrupt once the agent has started calling tools. shouldInject: ({ steps }) => steps.length > 0, }, run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal, // Required for injection. Without it nothing injects, and every // mid-turn message is answered as the next turn instead. ...chat.toStreamTextOptions(), }), });A declined message keeps its place in the queue, so it survives a crash
and is answered by whichever run picks the conversation up. An injected
one is consumed at the moment it is injected, so it is never also
answered as a later turn.Browser chats now keep the active turn open across page reloads when
older completion records are replayed.(#4643)
Add chat.endAndContinue() so fully hand-rolled custom chat agents
can hand a conversation off to a fresh run on the latest deployed task
version while preserving unconsumed Session input.(#4647)
Custom chat agents now validate and parse client data declared with
chat.withClientData({ schema }) before passing it to agent code.(#4646)
Bug fixes
Fixes a case where a chat could silently lose a message. If a message
arrived while the agent was between turns and a stop arrived after it,
the cursor the next boot resumed from could point past that message, so
it was never answered and no error was raised. This affected
chat.agent, not just custom agents.(#4644)
Fixes a recovered answer being cut off. After a crash the agent replays
the message it had not answered yet, but it was replaying the stop that
arrived after that message too, so the turn answering it was aborted the
moment it began. A stop is now only applied to the turn that was live
when it arrived. That holds however the stop got there: sent after the
last completed turn, or sent to a chat whose most recent turn was
completed by an older version of the SDK.
One limitation to know about: the recovered answer is persisted
correctly, but a chat page that stayed open across the crash keeps
showing the partial answer it had already received. Reload the page to
see the full recovered answer.Also fixes a retried send being answered twice. When a send was retried
and its idempotency claim was lost, the agent could consume the same
message a second time.Custom agent loops can now inspect pending chat input without consuming
it, and consume one record at a time, with chat.messages.hasPending()
and chat.messages.next(). Records carry stable identifiers so a
redelivery is recognisable.if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }hasPending() answers for messages alone, so a message sitting behind a
stop, or behind a record this version of the SDK does not recognise,
still reports as pending and is still delivered. Anything the agent has
no consumer for is discarded rather than left where it would make every
message queued behind it undeliverable. chat.messages.next() returning
undefined means no message became consumable before the timeout.chat.writeTurnComplete()'s sessionInEventId is the cursor that is
safe to resume from, not the sequence of the record the turn answered.
It is held back behind any message still waiting to be handled, so a
value below the record you just handled is expected.Fixed a chat agent hanging after an interrupted turn: when a run was
killed mid-answer (out of memory, crash, or eviction) and only the one
message it was answering was still outstanding, the new run never
replied to it. That message is now re-answered on the new run.(#4768)
Fix chat transport discarding the next turn after stopping generation.
skipToTurnComplete is now reset when a new message or action is sent,
so a message sent after stopGeneration streams normally instead of
leaving the chat stuck in a streaming state.(#4744)
Fixes a message sent while the agent was mid-answer being lost if the
run then crashed. The cursor written at the end of each turn could point
past a message that had arrived during that turn but had not been
answered yet, so the next boot skipped it and no error was raised
anywhere. Such a message is now held until a turn actually takes it.(#4795)
This also removes the in-memory buffer those messages used to sit in, on
both chat.agent and chat.createSession(), so a message waiting for
its turn is durable rather than only present in the worker that received
it.Server changes
These changes affect the self-hosted Docker image and Trigger.dev Cloud:
Self-hosted instances can now disable the admin dashboard and user
impersonation entirely. See the self-hosting docs for the new setting.(#4774)
The dashboard has two new themes, Black and White, plus appearance
options for stronger colors and underlined links.(#4547)
Deployment logs no longer jump to the bottom while you are reading
earlier output. Scroll up to pause auto-scroll, and scroll back down or
use the new scroll-to-bottom button in the log header to resume
following.(#4776)
Customize the runs list: show, hide, and reorder columns, and add
smart columns that pull a value straight out of a run's payload,
metadata, or output. Your column choices are saved in the page URL, so
you can share a view, bookmark it, or save it straight to your
favorites.(#4652)
Stop the browser offering to autofill or save environment variable
values as saved credentials.(#4777)
Cut webapp CPU usage by about a quarter on the routes that workers
call most, freeing headroom at the same request rate. Detailed
event-loop blocking traces are no longer recorded by default, because
producing them was itself a large part of that cost.(#4746)
When a runs list or runs.list API request spans too much data to
complete, it now returns a clear, actionable error asking you to narrow
the time range, instead of failing with a generic error.(#4773)
Improved the performance and reliability of the runs list and the
runs.list API, especially for large projects and filtered views.(#4763)
New Vercel connections now get version skew protection turned on
automatically, so each run uses the task version its deployment shipped
with. Automatic atomic deployments are deprecated and no longer offered
when you connect a project, but stay available in your Vercel
integration settings.(#4741)
The Staging branch setting now shows an upgrade prompt on plans that
don't include a Staging environment, instead of looking editable and
then silently doing nothing when saved.(#4784)
Raw changeset output
Releases
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
[email protected][email protected]
Patch Changes
trigger.dev deploy now asks the server whether to build with Depot
or the native build server unless --native-build, --depot-build, or
--local-build is passed, so the native build server can be rolled out
per organization without a CLI change. --local-bundle and --detach
now require --native-build.(#4803)
Add an experimental --local-bundle deploy flag that runs the install
and bundling steps on your machine and uploads only the build output;
the image is still built remotely. Useful when your project's install
step needs tooling or credentials that only exist locally.(#4331)
Send the CLI version header on all API requests so deployments are
attributable to a CLI version(#4778)
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]@trigger.dev/[email protected]
Patch Changes
trigger.dev deploy now asks the server whether to build with Depot
or the native build server unless --native-build, --depot-build, or
--local-build is passed, so the native build server can be rolled out
per organization without a CLI change. --local-bundle and --detach
now require --native-build.(#4803)
Add an experimental --local-bundle deploy flag that runs the install
and bundling steps on your machine and uploads only the build output;
the image is still built remotely. Useful when your project's install
step needs tooling or credentials that only exist locally.(#4331)
A message that arrives mid-turn and is not injected into that turn is
now answered as the next turn, instead of being dropped. This is what
the pendingMessages docs have always described, and it applies to the
default too: configuring pendingMessages without a shouldInject
declines every batch, which previously meant every mid-turn message was
lost with no error at either end.(#4795)
chat.agent({ id: "my-chat", pendingMessages: { onReceived: ({ message }) => logger.info("arrived mid-turn", { id: message.id }), // Only interrupt once the agent has started calling tools. shouldInject: ({ steps }) => steps.length > 0, }, run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal, // Required for injection. Without it nothing injects, and every // mid-turn message is answered as the next turn instead. ...chat.toStreamTextOptions(), }), });A declined message keeps its place in the queue, so it survives a crash
and is answered by whichever run picks the conversation up. An injected
one is consumed at the moment it is injected, so it is never also
answered as a later turn.Fixes a case where a chat could silently lose a message. If a message
arrived while the agent was between turns and a stop arrived after it,
the cursor the next boot resumed from could point past that message, so
it was never answered and no error was raised. This affected
chat.agent, not just custom agents.(#4644)
Fixes a recovered answer being cut off. After a crash the agent replays
the message it had not answered yet, but it was replaying the stop that
arrived after that message too, so the turn answering it was aborted the
moment it began. A stop is now only applied to the turn that was live
when it arrived. That holds however the stop got there: sent after the
last completed turn, or sent to a chat whose most recent turn was
completed by an older version of the SDK.
One limitation to know about: the recovered answer is persisted
correctly, but a chat page that stayed open across the crash keeps
showing the partial answer it had already received. Reload the page to
see the full recovered answer.Also fixes a retried send being answered twice. When a send was retried
and its idempotency claim was lost, the agent could consume the same
message a second time.Custom agent loops can now inspect pending chat input without consuming
it, and consume one record at a time, with chat.messages.hasPending()
and chat.messages.next(). Records carry stable identifiers so a
redelivery is recognisable.if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }hasPending() answers for messages alone, so a message sitting behind a
stop, or behind a record this version of the SDK does not recognise,
still reports as pending and is still delivered. Anything the agent has
no consumer for is discarded rather than left where it would make every
message queued behind it undeliverable. chat.messages.next() returning
undefined means no message became consumable before the timeout.chat.writeTurnComplete()'s sessionInEventId is the cursor that is
safe to resume from, not the sequence of the record the turn answered.
It is held back behind any message still waiting to be handled, so a
value below the record you just handled is expected.@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Fixed a chat agent hanging after an interrupted turn: when a run was
killed mid-answer (out of memory, crash, or eviction) and only the one
message it was answering was still outstanding, the new run never
replied to it. That message is now re-answered on the new run.(#4768)
Browser chats now keep the active turn open across page reloads when
older completion records are replayed.(#4643)
Add chat.endAndContinue() so fully hand-rolled custom chat agents
can hand a conversation off to a fresh run on the latest deployed task
version while preserving unconsumed Session input.(#4647)
Fix chat transport discarding the next turn after stopping generation.
skipToTurnComplete is now reset when a new message or action is sent,
so a message sent after stopGeneration streams normally instead of
leaving the chat stuck in a streaming state.(#4744)
Custom chat agents now validate and parse client data declared with
chat.withClientData({ schema }) before passing it to agent code.(#4646)
Fixes a message sent while the agent was mid-answer being lost if the
run then crashed. The cursor written at the end of each turn could point
past a message that had arrived during that turn but had not been
answered yet, so the next boot skipped it and no error was raised
anywhere. Such a message is now held until a turn actually takes it.(#4795)
This also removes the in-memory buffer those messages used to sit in, on
both chat.agent and chat.createSession(), so a message waiting for
its turn is durable rather than only present in the worker that received
it.A message that arrives mid-turn and is not injected into that turn is
now answered as the next turn, instead of being dropped. This is what
the pendingMessages docs have always described, and it applies to the
default too: configuring pendingMessages without a shouldInject
declines every batch, which previously meant every mid-turn message was
lost with no error at either end.(#4795)
chat.agent({ id: "my-chat", pendingMessages: { onReceived: ({ message }) => logger.info("arrived mid-turn", { id: message.id }), // Only interrupt once the agent has started calling tools. shouldInject: ({ steps }) => steps.length > 0, }, run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal, // Required for injection. Without it nothing injects, and every // mid-turn message is answered as the next turn instead. ...chat.toStreamTextOptions(), }), });A declined message keeps its place in the queue, so it survives a crash
and is answered by whichever run picks the conversation up. An injected
one is consumed at the moment it is injected, so it is never also
answered as a later turn.Fixes a case where a chat could silently lose a message. If a message
arrived while the agent was between turns and a stop arrived after it,
the cursor the next boot resumed from could point past that message, so
it was never answered and no error was raised. This affected
chat.agent, not just custom agents.(#4644)
Fixes a recovered answer being cut off. After a crash the agent replays
the message it had not answered yet, but it was replaying the stop that
arrived after that message too, so the turn answering it was aborted the
moment it began. A stop is now only applied to the turn that was live
when it arrived. That holds however the stop got there: sent after the
last completed turn, or sent to a chat whose most recent turn was
completed by an older version of the SDK.
One limitation to know about: the recovered answer is persisted
correctly, but a chat page that stayed open across the crash keeps
showing the partial answer it had already received. Reload the page to
see the full recovered answer.Also fixes a retried send being answered twice. When a send was retried
and its idempotency claim was lost, the agent could consume the same
message a second time.Custom agent loops can now inspect pending chat input without consuming
it, and consume one record at a time, with chat.messages.hasPending()
and chat.messages.next(). Records carry stable identifiers so a
redelivery is recognisable.if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }hasPending() answers for messages alone, so a message sitting behind a
stop, or behind a record this version of the SDK does not recognise,
still reports as pending and is still delivered. Anything the agent has
no consumer for is discarded rather than left where it would make every
message queued behind it undeliverable. chat.messages.next() returning
undefined means no message became consumable before the timeout.chat.writeTurnComplete()'s sessionInEventId is the cursor that is
safe to resume from, not the sequence of the record the turn answered.
It is held back behind any message still waiting to be handled, so a
value below the record you just handled is expected.Updated dependencies:
@trigger.dev/[email protected]Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Original source - Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
helm-v4.5.14: chore: release v4.5.14 (#4813)
Trigger.dev adds realtime stream resume and latest-tail subscriptions, plus refreshed access-token reconnects, bounded history, and a new useSessionStream hook. It also improves native build server deploy logs and fixes queue retries that could fail too early.
Summary
4 improvements, 1 bug fix.
Improvements
Native build server deploys now show a single updating build log line
by default; pass --build-logs full to stream every line (always used
in CI and when output is not a terminal).(#4817)
Realtime stream subscriptions can now refresh an expired access token
and reconnect, via a new optional refreshAccessToken option on the
client configuration and the React hooks.(#4811)
Subscribe to a realtime stream from its latest record instead of
replaying the whole history. Pass from: "latest" to
useRealtimeStream, streams.read(), or fetchStream to start at the
current tail (the latest record, then live updates) instead of replaying
(a live "last value" view), and maxParts to keep the accumulated
parts array bounded. A reconnect or remount resumes from the last
record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall
back to a full replay.(#4811)
useRealtimeStream also gains a lastEventId option and returns the
lastEventId of the last part seen, so you can persist the cursor (for
example across a page reload) and resume exactly where you left off. An
onParts callback delivers each throttled batch of parts with their
event ids.const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });Added a useSessionStream React hook for reading a session's output
or input channel in realtime. It accumulates records with automatic
resume from the last record you received, and supports from: "latest"
(start at the current tail, only new records after you connect),
maxRecords (keep a bounded number of records in memory), a
lastEventId resume cursor, and an onRecords callback that delivers
each throttled batch of records with their event ids.(#4811)
Server changes
These changes affect the self-hosted Docker image and Trigger.dev Cloud:
Task retries that wait in the queue no longer count against the
queue's internal redelivery limit, so runs with many long-delay retries
are not wrongly failed with TASK_RUN_DEQUEUED_MAX_RETRIES.(#4810)
Raw changeset output
Releases
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
[email protected]Patch Changes
Native build server deploys now show a single updating build log line
by default; pass --build-logs full to stream every line (always used
in CI and when output is not a terminal).(#4817)
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]@trigger.dev/[email protected]
Patch Changes
Realtime stream subscriptions can now refresh an expired access token
and reconnect, via a new optional refreshAccessToken option on the
client configuration and the React hooks.(#4811)
Subscribe to a realtime stream from its latest record instead of
replaying the whole history. Pass from: "latest" to
useRealtimeStream, streams.read(), or fetchStream to start at the
current tail (the latest record, then live updates) instead of replaying
(a live "last value" view), and maxParts to keep the accumulated
parts array bounded. A reconnect or remount resumes from the last
record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall
back to a full replay.(#4811)
useRealtimeStream also gains a lastEventId option and returns the
lastEventId of the last part seen, so you can persist the cursor (for
example across a page reload) and resume exactly where you left off. An
onParts callback delivers each throttled batch of parts with their
event ids.const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Realtime stream subscriptions can now refresh an expired access token
and reconnect, via a new optional refreshAccessToken option on the
client configuration and the React hooks.(#4811)
Subscribe to a realtime stream from its latest record instead of
replaying the whole history. Pass from: "latest" to
useRealtimeStream, streams.read(), or fetchStream to start at the
current tail (the latest record, then live updates) instead of replaying
(a live "last value" view), and maxParts to keep the accumulated
parts array bounded. A reconnect or remount resumes from the last
record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall
back to a full replay.(#4811)
useRealtimeStream also gains a lastEventId option and returns the
lastEventId of the last part seen, so you can persist the cursor (for
example across a page reload) and resume exactly where you left off. An
onParts callback delivers each throttled batch of parts with their
event ids.const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });Added a useSessionStream React hook for reading a session's output
or input channel in realtime. It accumulates records with automatic
resume from the last record you received, and supports from: "latest"
(start at the current tail, only new records after you connect),
maxRecords (keep a bounded number of records in memory), a
lastEventId resume cursor, and an onRecords callback that delivers
each throttled batch of records with their event ids.(#4811)
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]Patch Changes
Subscribe to a realtime stream from its latest record instead of
replaying the whole history. Pass from: "latest" to
useRealtimeStream, streams.read(), or fetchStream to start at the
current tail (the latest record, then live updates) instead of replaying
(a live "last value" view), and maxParts to keep the accumulated
parts array bounded. A reconnect or remount resumes from the last
record it saw, so no records are missed and none are replayed. from: "latest" needs a server that supports it; older servers safely fall
back to a full replay.(#4811)
useRealtimeStream also gains a lastEventId option and returns the
lastEventId of the last part seen, so you can persist the cursor (for
example across a page reload) and resume exactly where you left off. An
onParts callback delivers each throttled batch of parts with their
event ids.const { parts, lastEventId } = useRealtimeStream<Frame>(runId, "frames", { from: "latest", // skip history, start at the current tail maxParts: 1, // keep only the most recent frame lastEventId: savedCursor, // resume from a persisted cursor onParts: (batch) => save(batch.at(-1)?.id), // track the cursor accessToken, });Updated dependencies:
@trigger.dev/[email protected]Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Original source - Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
helm-v4.5.13: chore: release v4.5.13 (#4769)
Trigger.dev adds smarter deploy builds with server-selected native or Depot options, an experimental local-bundle flag, and CLI version reporting. It also improves chat message durability and recovery, plus dashboard themes, run list customization, and faster, more reliable runs lists.
Summary
4 new features, 12 improvements, 5 bug fixes.
Improvements
trigger.dev deploy now asks the server whether to build with Depot
or the native build server unless --native-build, --depot-build, or
--local-build is passed, so the native build server can be rolled out
per organization without a CLI change. --local-bundle and --detach
now require --native-build.
(#4803)Add an experimental --local-bundle deploy flag that runs the install
and bundling steps on your machine and uploads only the build output;
the image is still built remotely. Useful when your project's install
step needs tooling or credentials that only exist locally.
(#4331)Send the CLI version header on all API requests so deployments are
attributable to a CLI version
(#4778)A message that arrives mid-turn and is not injected into that turn is
now answered as the next turn, instead of being dropped. This is what
the pendingMessages docs have always described, and it applies to the
default too: configuring pendingMessages without a shouldInject
declines every batch, which previously meant every mid-turn message was
lost with no error at either end.
(#4795)chat.agent({ id: "my-chat", pendingMessages: { onReceived: ({ message }) => logger.info("arrived mid-turn", { id: message.id }), // Only interrupt once the agent has started calling tools. shouldInject: ({ steps }) => steps.length > 0, }, run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal, // Required for injection. Without it nothing injects, and every // mid-turn message is answered as the next turn instead. ...chat.toStreamTextOptions(), }), });A declined message keeps its place in the queue, so it survives a crash
and is answered by whichever run picks the conversation up. An injected
one is consumed at the moment it is injected, so it is never also
answered as a later turn.Browser chats now keep the active turn open across page reloads when
older completion records are replayed.
(#4643)Add chat.endAndContinue() so fully hand-rolled custom chat agents
can hand a conversation off to a fresh run on the latest deployed task
version while preserving unconsumed Session input.
(#4647)Custom chat agents now validate and parse client data declared with
chat.withClientData({ schema }) before passing it to agent code.
(#4646)Bug fixes
Fixes a case where a chat could silently lose a message. If a message
arrived while the agent was between turns and a stop arrived after it,
the cursor the next boot resumed from could point past that message, so
it was never answered and no error was raised. This affected
chat.agent, not just custom agents.
(#4644)Fixes a recovered answer being cut off. After a crash the agent replays
the message it had not answered yet, but it was replaying the stop that
arrived after that message too, so the turn answering it was aborted the
moment it began. A stop is now only applied to the turn that was live
when it arrived. That holds however the stop got there: sent after the
last completed turn, or sent to a chat whose most recent turn was
completed by an older version of the SDK.One limitation to know about: the recovered answer is persisted
correctly, but a chat page that stayed open across the crash keeps
showing the partial answer it had already received. Reload the page to
see the full recovered answer.Also fixes a retried send being answered twice. When a send was retried
and its idempotency claim was lost, the agent could consume the same
message a second time.Custom agent loops can now inspect pending chat input without consuming
it, and consume one record at a time, with chat.messages.hasPending()
and chat.messages.next(). Records carry stable identifiers so a
redelivery is recognisable.if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }hasPending() answers for messages alone, so a message sitting behind a
stop, or behind a record this version of the SDK does not recognise,
still reports as pending and is still delivered. Anything the agent has
no consumer for is discarded rather than left where it would make every
message queued behind it undeliverable. chat.messages.next() returning
undefined means no message became consumable before the timeout.chat.writeTurnComplete()'s sessionInEventId is the cursor that is
safe to resume from, not the sequence of the record the turn answered.
It is held back behind any message still waiting to be handled, so a
value below the record you just handled is expected.Fixed a chat agent hanging after an interrupted turn: when a run was
killed mid-answer (out of memory, crash, or eviction) and only the one
message it was answering was still outstanding, the new run never
replied to it. That message is now re-answered on the new run.
(#4768)Fix chat transport discarding the next turn after stopping generation.
skipToTurnComplete is now reset when a new message or action is sent,
so a message sent after stopGeneration streams normally instead of
leaving the chat stuck in a streaming state.
(#4744)Fixes a message sent while the agent was mid-answer being lost if the
run then crashed. The cursor written at the end of each turn could point
past a message that had arrived during that turn but had not been
answered yet, so the next boot skipped it and no error was raised
anywhere. Such a message is now held until a turn actually takes it.
(#4795)This also removes the in-memory buffer those messages used to sit in, on
both chat.agent and chat.createSession(), so a message waiting for
its turn is durable rather than only present in the worker that received
it.Server changes
These changes affect the self-hosted Docker image and Trigger.dev Cloud:
Self-hosted instances can now disable the admin dashboard and user
impersonation entirely. See the self-hosting docs for the new setting.
(#4774)The dashboard has two new themes, Black and White, plus appearance
options for stronger colors and underlined links.
(#4547)Deployment logs no longer jump to the bottom while you are reading
earlier output. Scroll up to pause auto-scroll, and scroll back down or
use the new scroll-to-bottom button in the log header to resume
following.
(#4776)Customize the runs list: show, hide, and reorder columns, and add
smart columns that pull a value straight out of a run's payload,
metadata, or output. Your column choices are saved in the page URL, so
you can share a view, bookmark it, or save it straight to your
favorites.
(#4652)Stop the browser offering to autofill or save environment variable
values as saved credentials.
(#4777)Cut webapp CPU usage by about a quarter on the routes that workers
call most, freeing headroom at the same request rate. Detailed
event-loop blocking traces are no longer recorded by default, because
producing them was itself a large part of that cost.
(#4746)When a runs list or runs.list API request spans too much data to
complete, it now returns a clear, actionable error asking you to narrow
the time range, instead of failing with a generic error.
(#4773)Improved the performance and reliability of the runs list and the
runs.list API, especially for large projects and filtered views.
(#4763)New Vercel connections now get version skew protection turned on
automatically, so each run uses the task version its deployment shipped
with. Automatic atomic deployments are deprecated and no longer offered
when you connect a project, but stay available in your Vercel
integration settings.
(#4741)The Staging branch setting now shows an upgrade prompt on plans that
don't include a Staging environment, instead of looking editable and
then silently doing nothing when saved.
(#4784)Raw changeset output
Releases
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
Patch Changes
trigger.dev deploy now asks the server whether to build with Depot
or the native build server unless --native-build, --depot-build, or
--local-build is passed, so the native build server can be rolled out
per organization without a CLI change. --local-bundle and --detach
now require --native-build.
(#4803)Add an experimental --local-bundle deploy flag that runs the install
and bundling steps on your machine and uploads only the build output;
the image is still built remotely. Useful when your project's install
step needs tooling or credentials that only exist locally.
(#4331)Send the CLI version header on all API requests so deployments are
attributable to a CLI version
(#4778)Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
trigger.dev deploy now asks the server whether to build with Depot
or the native build server unless --native-build, --depot-build, or
--local-build is passed, so the native build server can be rolled out
per organization without a CLI change. --local-bundle and --detach
now require --native-build.
(#4803)Add an experimental --local-bundle deploy flag that runs the install
and bundling steps on your machine and uploads only the build output;
the image is still built remotely. Useful when your project's install
step needs tooling or credentials that only exist locally.
(#4331)A message that arrives mid-turn and is not injected into that turn is
now answered as the next turn, instead of being dropped. This is what
the pendingMessages docs have always described, and it applies to the
default too: configuring pendingMessages without a shouldInject
declines every batch, which previously meant every mid-turn message was
lost with no error at either end.
(#4795)chat.agent({ id: "my-chat", pendingMessages: { onReceived: ({ message }) => logger.info("arrived mid-turn", { id: message.id }), // Only interrupt once the agent has started calling tools. shouldInject: ({ steps }) => steps.length > 0, }, run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal, // Required for injection. Without it nothing injects, and every // mid-turn message is answered as the next turn instead. ...chat.toStreamTextOptions(), }), });A declined message keeps its place in the queue, so it survives a crash
and is answered by whichever run picks the conversation up. An injected
one is consumed at the moment it is injected, so it is never also
answered as a later turn.Fixes a case where a chat could silently lose a message. If a message
arrived while the agent was between turns and a stop arrived after it,
the cursor the next boot resumed from could point past that message, so
it was never answered and no error was raised. This affected
chat.agent, not just custom agents.
(#4644)Fixes a recovered answer being cut off. After a crash the agent replays
the message it had not answered yet, but it was replaying the stop that
arrived after that message too, so the turn answering it was aborted the
moment it began. A stop is now only applied to the turn that was live
when it arrived. That holds however the stop got there: sent after the
last completed turn, or sent to a chat whose most recent turn was
completed by an older version of the SDK.One limitation to know about: the recovered answer is persisted
correctly, but a chat page that stayed open across the crash keeps
showing the partial answer it had already received. Reload the page to
see the full recovered answer.Also fixes a retried send being answered twice. When a send was retried
and its idempotency claim was lost, the agent could consume the same
message a second time.Custom agent loops can now inspect pending chat input without consuming
it, and consume one record at a time, with chat.messages.hasPending()
and chat.messages.next(). Records carry stable identifiers so a
redelivery is recognisable.if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }hasPending() answers for messages alone, so a message sitting behind a
stop, or behind a record this version of the SDK does not recognise,
still reports as pending and is still delivered. Anything the agent has
no consumer for is discarded rather than left where it would make every
message queued behind it undeliverable. chat.messages.next() returning
undefined means no message became consumable before the timeout.chat.writeTurnComplete()'s sessionInEventId is the cursor that is
safe to resume from, not the sequence of the record the turn answered.
It is held back behind any message still waiting to be handled, so a
value below the record you just handled is expected.@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Updated dependencies:
@trigger.dev/[email protected]
@trigger.dev/[email protected]
Patch Changes
Fixed a chat agent hanging after an interrupted turn: when a run was
killed mid-answer (out of memory, crash, or eviction) and only the one
message it was answering was still outstanding, the new run never
replied to it. That message is now re-answered on the new run.
(#4768)Browser chats now keep the active turn open across page reloads when
older completion records are replayed.
(#4643)Add chat.endAndContinue() so fully hand-rolled custom chat agents
can hand a conversation off to a fresh run on the latest deployed task
version while preserving unconsumed Session input.
(#4647)Fix chat transport discarding the next turn after stopping generation.
skipToTurnComplete is now reset when a new message or action is sent,
so a message sent after stopGeneration streams normally instead of
leaving the chat stuck in a streaming state.
(#4744)Custom chat agents now validate and parse client data declared with
chat.withClientData({ schema }) before passing it to agent code.
(#4646)Fixes a message sent while the agent was mid-answer being lost if the
run then crashed. The cursor written at the end of each turn could point
past a message that had arrived during that turn but had not been
answered yet, so the next boot skipped it and no error was raised
anywhere. Such a message is now held until a turn actually takes it.
(#4795)This also removes the in-memory buffer those messages used to sit in, on
both chat.agent and chat.createSession(), so a message waiting for
its turn is durable rather than only present in the worker that received
it.A message that arrives mid-turn and is not injected into that turn is
now answered as the next turn, instead of being dropped. This is what
the pendingMessages docs have always described, and it applies to the
default too: configuring pendingMessages without a shouldInject
declines every batch, which previously meant every mid-turn message was
lost with no error at either end.
(#4795)chat.agent({ id: "my-chat", pendingMessages: { onReceived: ({ message }) => logger.info("arrived mid-turn", { id: message.id }), // Only interrupt once the agent has started calling tools. shouldInject: ({ steps }) => steps.length > 0, }, run: async ({ messages, signal }) => streamText({ model, messages, abortSignal: signal, // Required for injection. Without it nothing injects, and every // mid-turn message is answered as the next turn instead. ...chat.toStreamTextOptions(), }), });A declined message keeps its place in the queue, so it survives a crash
and is answered by whichever run picks the conversation up. An injected
one is consumed at the moment it is injected, so it is never also
answered as a later turn.Fixes a case where a chat could silently lose a message. If a message
arrived while the agent was between turns and a stop arrived after it,
the cursor the next boot resumed from could point past that message, so
it was never answered and no error was raised. This affected
chat.agent, not just custom agents.
(#4644)Fixes a recovered answer being cut off. After a crash the agent replays
the message it had not answered yet, but it was replaying the stop that
arrived after that message too, so the turn answering it was aborted the
moment it began. A stop is now only applied to the turn that was live
when it arrived. That holds however the stop got there: sent after the
last completed turn, or sent to a chat whose most recent turn was
completed by an older version of the SDK.One limitation to know about: the recovered answer is persisted
correctly, but a chat page that stayed open across the crash keeps
showing the partial answer it had already received. Reload the page to
see the full recovered answer.Also fixes a retried send being answered twice. When a send was retried
and its idempotency claim was lost, the agent could consume the same
message a second time.Custom agent loops can now inspect pending chat input without consuming
it, and consume one record at a time, with chat.messages.hasPending()
and chat.messages.next(). Records carry stable identifiers so a
redelivery is recognisable.if (await chat.messages.hasPending()) { const record = await chat.messages.next({ timeoutInSeconds: 0 }); if (record) handle(record.payload); }hasPending() answers for messages alone, so a message sitting behind a
stop, or behind a record this version of the SDK does not recognise,
still reports as pending and is still delivered. Anything the agent has
no consumer for is discarded rather than left where it would make every
message queued behind it undeliverable. chat.messages.next() returning
undefined means no message became consumable before the timeout.chat.writeTurnComplete()'s sessionInEventId is the cursor that is
safe to resume from, not the sequence of the record the turn answered.
It is held back behind any message still waiting to be handled, so a
value below the record you just handled is expected.Updated dependencies:
@trigger.dev/[email protected]
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Original source - Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
docs-release-2026-08-28
Trigger.dev publishes docs for chat agent custom-agent APIs and version skew protection.
Publish docs: chat agent custom-agent APIs, version skew protection, …
Original source - Aug 28, 2026
- Date parsed from source:Aug 28, 2026
- First seen by Releasebot:Aug 29, 2026
docs-release-2026-08-28-2
Trigger.dev adds docs for realtime start-from-latest streams and useSessionStream support.
Publish docs: realtime start-from-latest streams and useSessionStream…
Original source - Aug 20, 2026
- Date parsed from source:Aug 20, 2026
- First seen by Releasebot:Aug 20, 2026
Trigger.dev v4.5.12
Trigger.dev releases execution windows for declarative scheduled tasks, plus faster builds, clearer deployment tracing, Node.js 24 defaults, and a set of reliability fixes for queues, metrics, observability, and run versioning.
1 new feature, 5 improvements, 4 bug fixes, and 17 server changes.
Highlights
Execution windows for declarative scheduled tasks
Declarative scheduled tasks now support configurable execution windows. Instead of running at precisely the CRON time, each run gets assigned a stable slot within the window, so the task reliably runs at the same offset on every invocation.
The Schedule API now exposes both the nominal CRON time (when the pattern fires) and the assigned execution time. The run payload gives you access to both. The dashboard shows the configured window for each schedule and lists upcoming assignment times.
(#4572)
Scheduled tasks docs
Improvements
- trigger.dev deploy --external-id tags a deployment with an identifier you control: a commit SHA, a CI run ID, a release tag. Deploying the same ID twice builds nothing and reports the existing version instead; use --force to rebuild. (#4663)
- trigger projects list shows the current Production runtime for every accessible project. Add --needs-update to filter for projects still on Node.js 21. (#4659)
- New projects from trigger init now use Node.js 24 by default. Deployments without an explicit runtime pick up their project's configured default. (#4649)
- Deployment builds now use custom base layer images and skip system package installation on every build, improving layer cache hits and pulling faster on worker nodes. (#4602)
- Set TRIGGER_EXTERNAL_DEPLOYMENT_ID to pin runs to the deployment your calling code came from, so an old release never triggers tasks from a new one. Set TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION=1 to detect the commit automatically on Vercel and most CI systems. Runs triggered before the build finishes wait, then start pinned. (#4664)
Bug fixes
- Unrelated runs no longer get merged into a single trace in external observability tools when they happen to execute on the same warm worker process. (#4534)
- Task metrics no longer go missing for projects that configure their own metricExporters or metricReaders, and the flush error that came with it is fixed. (#4613)
- idempotencyKeys.reset() now works when the idempotency key is exactly 64 characters long. Previously, any 64-character key was treated as already hashed, so passing one with a scope silently ignored the scope and the reset never found a match. (#4626)
- Fair queue tenants can no longer get permanently stuck behind leaked concurrency slots. Slots are freed on every path that finishes a message, a failed release no longer causes a message to run twice or lose its retry, and a background sweep recovers any leaked slot so queues recover without manual cleanup. (#4540)
Server changes
These changes are included in the v4.5.12 Docker image and are already live on Trigger.dev Cloud:
- Deployments and runs now display the external ID they were tagged or pinned with, so you can trace a run back to the specific release of your app. (#4665)
- Operators can now route an organization's runs to specific Kubernetes node pools. (#4655)
- Dashboard pages load faster on projects with many preview branches. (#4606)
- Global log search now supports faster bounded substring matching and clearer time-range expansion. (#4615)
- Task triggering is now more resilient to brief, transient service interruptions. (#4623)
- Failed AI SDK tool call and embedding spans now show the error message and stack trace in the run inspector. (#4653)
- Archiving a branch now returns you to the same page of the branches list, preserving your search and filters. (#4724)
- Using * as a concurrency key no longer stalls the entire queue. Previously, a single run with that key could block all other runs on the queue until something else was triggered. (#4628)
- Fixed a window after promoting or rolling back a deployment where newly triggered runs could still execute on the previous version. New runs now pick up the current version immediately. (#4622)
- Root API keys no longer show an environment creation timestamp as their creation date. (#4612)
- The app version shown on the organization settings page now reports the real version instead of v0.0.0. (#4611)
- A paused environment now stays paused after a deploy. Previously a new deployment could restart execution on a paused environment. (#4625)
- Alert webhook destinations in reserved benchmarking IP ranges are now rejected. (#4735)
- TRQL queries using the PREWHERE clause are now rejected with a clear error. Use WHERE instead, which is filtered the same way but preserves data isolation guarantees. (#4735)
- Run trace rows now respond consistently to mouse and keyboard selection, including Alt-click expansion controls. (#4701)
- The "Back to app" button in organization settings now returns you to that specific organization instead of your most recently visited one. (#4632)
- Runs triggered with a ttl that were requeued after a failure once their TTL had elapsed could get permanently stuck in the queued state. Requeued runs now dequeue normally: a run's TTL only applies while it's waiting to start for the first time. (#4669)
How to upgrade
Update the trigger.dev/* packages to v4.5.12 using your package manager:
npx trigger.dev@latest update # npm pnpm dlx trigger.dev@latest update # pnpm yarn dlx trigger.dev@latest update # yarn bunx trigger.dev@latest update # bunSelf-hosted users: update your Docker image to ghcr.io/triggerdotdev/trigger.dev:v4.5.12.
Original source - Aug 20, 2026
- Date parsed from source:Aug 20, 2026
- First seen by Releasebot:Aug 20, 2026
trigger.dev v4.5.12
Trigger.dev releases v4.5.12 with stable execution windows for scheduled tasks, deployment external IDs and run pinning, faster builds and log search, plus fixes for queue stalls, paused environments, TTL retries, and observability tracing.
trigger.dev v4.5.12
Upgrade
npx trigger.dev@latest update # npm
pnpm dlx trigger.dev@latest update # pnpm
yarn dlx trigger.dev@latest update # yarn
bunx trigger.dev@latest update # bun
Self-hosted Docker image: ghcr.io/triggerdotdev/trigger.dev:v4.5.12
Release notes
Read the full release notes: https://trigger.dev/changelog/v4-5-12
What's changed
Highlights
Define stable execution windows on declarative scheduled tasks. Schedule API responses now expose both the nominal CRON time and its assigned time, while the dashboard shows configured windows and upcoming assignments. (#4572)
Improvements
trigger.dev deploy --external-id tags a deployment with an id of your own — a commit SHA, a CI run id, a release tag — so runs triggered by that release of your app go to that deployment. Deploying an id that is already deployed builds nothing and reports the existing version instead of creating a duplicate; use --force to rebuild it. (#4663)
List the current Production runtime for every accessible project with trigger projects list. Add --needs-update to identify projects currently running Node.js 21. (#4659)
New projects created with trigger init use Node.js 24 by default. Deployments without explicit runtime now use their project's configured default runtime. (#4649)
Deployment builds now use custom base layer images and no longer install system packages during every build. This improves layer caching resulting in both faster deployments and faster image pulls on the worker cluster side. (#4602)
Unrelated runs are no longer merged into a single trace in your external observability tool when they happen to execute on the same warm worker process. (#4534)
Task metrics no longer go missing for projects that configure their own metricExporters or metricReaders, and the flush error that came with it is gone. (#4613)
idempotencyKeys.reset() now works when your idempotency key is itself 64 characters long (for example if you use a hash of your own as the key). Previously any 64-character key was assumed to be already hashed, so passing one along with a scope silently ignored the scope and the reset never found a matching run. Keys returned by idempotencyKeys.create() continue to be reset exactly as before. (#4626)
Pin runs to the deployment your calling code came from, so an old release never triggers tasks from a new one: set TRIGGER_EXTERNAL_DEPLOYMENT_ID to the id you deployed with, or TRIGGER_AUTOMATIC_SKEW_VERSION_PROTECTION=1 to detect the commit automatically on Vercel and most CI systems. Runs triggered before that deployment finishes building wait for it, then start pinned. (#4664)
Fair queue tenants can no longer get permanently stuck behind leaked concurrency slots. Slots are now freed on every path that finishes a message, a failed release no longer causes a message to run twice or lose its retry, and a background sweep frees any slot that does leak, so a tenant's queues recover on their own instead of needing manual cleanup. (#4540)
Server changes
These changes affect the self-hosted Docker image and Trigger.dev Cloud:
Deployments and runs now show the external ID they were deployed or pinned with, so you can trace a run back to the release of your app that triggered it. (#4665)
Operators can now route an organization's runs to specific Kubernetes node pools. (#4655)
Dashboard pages load faster on projects with many preview branches by no longer loading every environment on each page. (#4606)
Global log search now supports faster bounded substring matching and clearer time-range expansion. (#4615)
Triggering tasks is now more resilient to brief, transient service interruptions, so short stalls are less likely to surface as errors. (#4623)
Failed AI SDK tool call and embedding spans now show the error message and stack trace in the run inspector, below the tool input. (#4653)
Archiving a branch now returns you to the same page of the branches list, keeping your place, search and filters instead of resetting to the first page. (#4724)
Using * as a concurrency key no longer stops a queue from being processed. Triggering a single run with that key could leave the whole queue stalled, including runs using other concurrency keys on it, until something else was triggered on the same queue. (#4628)
Fixed a brief window after promoting or rolling back a deployment where newly triggered runs could still execute on the previous version. New runs now pick up the current version immediately. (#4622)
Root API keys no longer show an environment creation timestamp as their creation date. (#4612)
The app version shown on the organization settings page now reports the real version instead of v0.0.0. (#4611)
Fix paused environments starting to run work again after a deploy: a paused environment now stays paused until you resume it. (#4625)
Reject alert webhook destinations in reserved benchmarking IP ranges. (#4735)
TRQL queries using the PREWHERE clause are now rejected with a clear error message. Use WHERE instead, which is filtered the same way but keeps your data isolation guarantees intact. (#4735)
Run trace rows now respond consistently to mouse and keyboard selection, including Alt-click expansion controls. (#4701)
The "Back to app" button in organization settings now returns you to that organization instead of your most recently used one. (#4632)
Runs triggered with a ttl could get permanently stuck in the queued state if they started executing and were then requeued after a failure (for example a worker dying mid-run) once the TTL had already elapsed. Requeued runs now dequeue normally: a run's TTL only applies while it is waiting to start for the first time. (#4669)
All packages: v4.5.12
@trigger.dev/build, @trigger.dev/core, @trigger.dev/python, @trigger.dev/react-hooks, @trigger.dev/redis-worker, @trigger.dev/rsc, @trigger.dev/schema-to-json, @trigger.dev/sdk, trigger.dev
Contributors
Chris Arderne, @nicktrn, Eric Allam, Oskar Otwinowski, claude[bot], Matt Aitken, Saadi Myftija, github-actions[bot], @NERLOE, Katia Bulatova, Wes Mason
Full changelog
v4.5.11...v4.5.12
Original source - Aug 20, 2026
- Date parsed from source:Aug 20, 2026
- First seen by Releasebot:Aug 20, 2026
- Aug 20, 2026
- Date parsed from source:Aug 20, 2026
- First seen by Releasebot:Aug 20, 2026
Helm Chart 4.5.12
Trigger.dev ships Helm chart 4.5.12 with release changes.
Installation
helm upgrade --install trigger \ oci://ghcr.io/triggerdotdev/charts/trigger \ --version "4.5.12"Changes
See commit history for detailed changes in this release.
Original source - Aug 18, 2026
- Date parsed from source:Aug 18, 2026
- First seen by Releasebot:Aug 19, 2026
re2-test-supervisor-runtime-uid: feat(supervisor): configurable security context for run pods
Trigger.dev adds KUBERNETES_RUNNER_SECURITY_CONTEXT to let Kubernetes run containers use baseline or restricted security settings.
Adds KUBERNETES_RUNNER_SECURITY_CONTEXT (off | baseline | restricted), selecting how constrained the run container is.
baseline drops the capability bounding set and blocks privilege escalation. restricted additionally pins the container to a non-root uid, chosen by runtime so bun images get their own.
Default is off, so this is inert on merge.
Original source
Curated by the Releasebot team
Releasebot is an aggregator of official release notes from hundreds of software vendors and thousands of sources.
Our editorial process involves the manual review and audit of release notes procured with the help of automated systems.