Skip to content

test(e2e): add Bun runtime coverage on Vercel#2870

Draft
NathanColosimo wants to merge 5 commits into
mainfrom
nathanc/add-bun-e2e-testing
Draft

test(e2e): add Bun runtime coverage on Vercel#2870
NathanColosimo wants to merge 5 commits into
mainfrom
nathanc/add-bun-e2e-testing

Conversation

@NathanColosimo

@NathanColosimo NathanColosimo commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a Next.js Turbopack workbench that builds and runs on Vercel's managed Bun 1.x runtime
  • add a Bun lane to the existing Vercel production E2E matrix while reusing every nextjs-turbopack test gate
  • keep Bun diagnostics and result artifacts separate from the Node.js control lane
  • allow only the experimental Bun deployment/test steps to fail, preserving a warning, runtime logs, summaries, and artifacts without turning the job red

Why

Workflow has accumulated several Bun-related reports, including #1735. This adds a durable Node-vs-Bun comparison on the same stable Next.js/Turbopack app and full E2E suite.

Baseline findings

Validated locally with Bun 1.3.14 and the current stable Next.js 16.2.10:

  • pnpm build passes
  • WORKFLOW_PUBLIC_MANIFEST=1 pnpm --filter nextjs-turbopack-bun build passes
  • the full existing E2E suite runs: 152 passed, 1 failed
  • the sole Bun failure is fetchWorkflow: __builtin_response_json retries three times and fails with JSON Parse error: Unexpected EOF

Validated on a manually built Vercel preview with managed Bun 1.3.12:

  • Next.js 16.2.10 + Turbopack builds successfully under bun run --bun
  • the runtime probe reports Bun 1.3.12 (process.versions.bun agrees)
  • cborReplayRegressionWorkflow completes with the expected result: 1,954 serialized bytes, 8 batches, and 40 documents
  • fetchWorkflow fails inside the Bun deployment with WORLD_CONTRACT_ERROR: Unexpected end of CBOR data
  • reading run.returnValue from a Bun route can also truncate the Workflow /v2/runs CBOR response; the Node CLI reads the same completed run and output successfully

This points to a broader Bun response-body truncation problem affecting both JSON/stream bodies locally and CBOR API responses on Vercel, rather than the original #1735 workload remaining broken.

Manual preview: https://workbench-bun-workflow-aqm89s50p.labs.vercel.dev

The non-blocking behavior is confirmed in Tests run 29125724275: the Bun test command failed, runtime logs and artifacts uploaded, the job emitted Experimental Bun E2E failure, and the Bun check concluded successfully. The manually attached preview could not accept the runner's GitHub OIDC trusted-source token, so that run validates failure reporting rather than the Bun suite itself; connecting the Vercel project to Git is still required for representative automated results.

Vercel project prerequisite

The matrix points to the dormant Labs project workbench-bun-workflow (prj_lb5X39knEIn63kRAoeNFipevjJBu), which was created for the old abandoned workbench/bun experiment. It currently has no Git link and still points at the removed workbench/bun root.

A Vercel project owner needs to:

  1. set the root directory to workbench/nextjs-turbopack-bun
  2. connect it to vercel/workflow with main as the production branch

My Labs role can read and link the project locally but receives 403 for project updates. Until the project is configured, the new non-blocking CI lane is expected to stop at Waiting for the Vercel deployment.

Validation

  • pnpm install --frozen-lockfile --lockfile-only
  • pnpm build
  • pnpm --filter @workflow/core typecheck
  • WORKFLOW_PUBLIC_MANIFEST=1 pnpm --filter nextjs-turbopack-bun build
  • full local production E2E suite under Bun: 152 passed, 1 failed
  • manual Vercel preview build under Bun 1.3.12
  • deployed Bun runtime probe
  • in-deployment execution plus Node-side inspection of the CBOR regression and fetchWorkflow runs
  • YAML parse, Biome check, and git diff --check
  • pnpm changeset status --since=main: no changeset needed

@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: abe2892

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

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Jul 10, 2026 9:50pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment Jul 10, 2026 9:50pm
example-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-astro-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-express-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-fastify-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-hono-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-nitro-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-nuxt-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-sveltekit-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-tanstack-start-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workbench-vite-workflow Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workflow-docs Ready Ready Preview, Comment, Open in v0 Jul 10, 2026 9:50pm
workflow-swc-playground Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workflow-tarballs Ready Ready Preview, Comment Jul 10, 2026 9:50pm
workflow-web Ready Ready Preview, Comment Jul 10, 2026 9:50pm

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
❌ ▲ Vercel Production 1454 152 254 1860
✅ 💻 Local Development 1483 0 222 1705
✅ 📦 Local Production 1617 0 243 1860
✅ 🐘 Local Postgres 1617 0 243 1860
✅ 🪟 Windows 153 0 2 155
✅ 📋 Other 894 0 191 1085
Total 7218 152 1155 8525

❌ Failed Tests

▲ Vercel Production (152 failed)

nextjs-turbopack-bun (151 failed):

  • DurableAgent e2e core basic text response
  • DurableAgent e2e core single tool call
  • DurableAgent e2e core multiple sequential tool calls
  • DurableAgent e2e core tool error recovery
  • DurableAgent e2e onStepFinish fires constructor + stream callbacks in order with step data
  • DurableAgent e2e onFinish fires constructor + stream callbacks in order with event data
  • DurableAgent e2e provider tools provider tool identity preserved across step boundaries
  • DurableAgent e2e provider tools mixed provider and function tools
  • DurableAgent e2e instructions string instructions are passed to the model
  • DurableAgent e2e timeout completes within timeout
  • DurableAgent e2e experimental_onStart (GAP) completes but callbacks are not called (GAP)
  • DurableAgent e2e experimental_onStepStart (GAP) completes but callbacks are not called (GAP)
  • DurableAgent e2e experimental_onToolCallStart (GAP) completes but callbacks are not called (GAP)
  • DurableAgent e2e experimental_onToolCallFinish (GAP) completes but callbacks are not called (GAP)
  • DurableAgent e2e prepareCall (GAP) completes but prepareCall is not applied (GAP)
  • DurableAgent e2e prepareStep on constructor agent-level prepareStep is called for each LLM step
  • DurableAgent e2e prepareStep on constructor stream-level prepareStep overrides constructor-level
  • DurableAgent e2e multimodal tool results passes through LanguageModelV3ToolResultOutput from tools
  • DurableAgent e2e tool approval (GAP) completes but needsApproval is not checked (GAP)
  • addTenWorkflow | wrun_01KX7013ME5ANYCFV2V9E6VQE5 | 🔍 observability
  • addTenWorkflow | wrun_01KX7013ME5ANYCFV2V9E6VQE5 | 🔍 observability
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KX701G42HHF02B0RH1WT2N1S | 🔍 observability
  • promiseAllWorkflow | wrun_01KX7018T3KKW63ZFN4Z89BJBK | 🔍 observability
  • promiseRaceWorkflow | wrun_01KX701D1D60ND508RDZXG32K2 | 🔍 observability
  • promiseAnyWorkflow | wrun_01KX7022GRV46BVSE2HKV0VGXK | 🔍 observability
  • importedStepOnlyWorkflow | wrun_01KX702MK6YQPHBBF0XN03G7BK | 🔍 observability
  • readableStreamWorkflow | wrun_01KX702A6MYQWSBF56D47TVQ5R | 🔍 observability
  • hookWorkflow | wrun_01KX702Q3NRAWW6PHSQ7E8EJNW | 🔍 observability
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KX702XR8QKWFDAJT4GBJT4F0 | 🔍 observability
  • webhookWorkflow | wrun_01KX7031WSJKPZAF498C570BNM | 🔍 observability
  • parallelStepsThenWebhookWorkflow - no hook_conflict from same-tick replay race | wrun_01KX7037EPDF03CFK2SYWK4W6A | 🔍 observability
  • webhook route with invalid token
  • sleepingWorkflow | wrun_01KX703Z09QJ9J020W3SBK05Q7 | 🔍 observability
  • parallelSleepWorkflow | wrun_01KX704B4VA2A9DX7ZW49CPZKM | 🔍 observability
  • sleepWinsRaceWorkflow | wrun_01KX704EE5WBYYM6AP3511WSCR | 🔍 observability
  • stepWinsRaceWorkflow | wrun_01KX704HH5CWM9N57C5VTJM7W4 | 🔍 observability
  • nullByteWorkflow | wrun_01KX704MYFBWJ68ANZ41Q825HS | 🔍 observability
  • workflowAndStepMetadataWorkflow | wrun_01KX704PYT7G2C0XGMSDQGFXBY | 🔍 observability
  • outputStreamWorkflow no startIndex (reads all chunks)
  • outputStreamWorkflow positive startIndex (skips first chunk)
  • outputStreamWorkflow negative startIndex (reads from end)
  • outputStreamWorkflow - getTailIndex and getChunks getTailIndex returns correct index after stream completes
  • outputStreamWorkflow - getTailIndex and getChunks getTailIndex returns -1 before any chunks are written
  • outputStreamWorkflow - getTailIndex and getChunks getChunks returns same content as reading the stream
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions | wrun_01KX706S18751DFZD74H9BNSEP | 🔍 observability
  • utf8StreamWorkflow | wrun_01KX7073XMK9QTBQ10B46YGNRC | 🔍 observability
  • writableForwardedFromWorkflowWorkflow | wrun_01KX707ACC2084234VF826TF31 | 🔍 observability
  • writableForwardedFromStepWorkflow | wrun_01KX707GD3JEK04KEVYY5ZV872 | 🔍 observability
  • fetchWorkflow | wrun_01KX707PKAVYRCZVK1BRK1ZHAB | 🔍 observability
  • Bun runtime version
  • CBOR event replay with cumulative step I/O (#1735) | wrun_01KX709D6BH6G51EWP5QQQCP2H | 🔍 observability
  • promiseRaceStressTestWorkflow | wrun_01KX707RGN1R18R36VJ0X1SPTC | 🔍 observability
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • error handling catchability step throw round-trips FatalError with cause chain to workflow catch
  • error handling catchability workflow throw round-trips FatalError + cause through run_failed event
  • error handling catchability workflow throw of a non-Error value round-trips verbatim as cause
  • error handling catchability step throw of a non-Error value preserves it as cause on the wrapping FatalError
  • error handling not registered WorkflowNotRegisteredError fails the run when workflow does not exist
  • error handling not registered StepNotRegisteredError fails the step but workflow can catch it
  • error handling not registered StepNotRegisteredError fails the run when not caught in workflow
  • stepDirectCallWorkflow - calling step functions directly outside workflow context
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KX70BHVQCKN44QDY5YQPQF53 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KX70BX3XMSB46TG0P5RBE1SC | 🔍 observability
  • hookGetConflictWorkflow - awaiting hook.getConflict() registers hook without payload | wrun_01KX70C8PD0JGCBN4H6758XWTS | 🔍 observability
  • 'hookGetConflictWithPriorStepWorkflow' - hook.getConflict() does not block step execution | wrun_01KX70CAY5GEZG8CR5WRFQC27P | 🔍 observability
  • 'hookGetConflictWithParallelStepWorkfl…' - hook.getConflict() does not block step execution | wrun_01KX70CDATH5FHKR0NJCDQ0C95 | 🔍 observability
  • hookGetConflictThenStepParallelWorkflow - hook.getConflict() continuation step runs alongside other steps | wrun_01KX70CFG7T25XN6Y5KDWREE1V | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_01KX70CX7FCZSDQH6Z8W3ND513 | 🔍 observability
  • hookClaimOnlyMutexWorkflow - hook works as a pure run mutex without payload data | wrun_01KX70DPH7B3P2GF1JC8D8F1NJ | 🔍 observability
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue | wrun_01KX70DSGTD7DTVH4520X9NM08 | 🔍 observability
  • hookSignalOwnerWorkflow - duplicate forwards its payload to the owner via resumeHook | wrun_01KX70DYG02KWM43WDDDE102RF | 🔍 observability
  • hookSupersedeOwnerWorkflow - duplicate cancels the owner and claims the released token | wrun_01KX70E21ZX22DNFWF7DPEYQQE | 🔍 observability
  • resume-or-start route pattern - resumeHook retried after start() reaches the new run | wrun_01KX70EAFNWPKK111SAMXA6EXH | 🔍 observability
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KX70EGWF6RGTVFEXDDJJAG3B | 🔍 observability
  • hookTokenReuseLoopWorkflow - same run recreates a hook with the same token after dispose() | wrun_01KX70EZ0GDGDZHXCYW0ZJT2K7 | 🔍 observability
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KX70F9QE3WG47CKAJCW59GWD | 🔍 observability
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KX70FJEXT57S2BZ36CPX2257 | 🔍 observability
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KX70FQTQ0Q2KERDQBE96RQV9 | 🔍 observability
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KX70FSSDNR5SWF4WG5XZ39KD | 🔍 observability
  • runClassSerializationWorkflow - Run instances serialize across workflow/step boundaries | wrun_01KX70G3C7GMJ2ABQCWTXQ9NJQ | 🔍 observability
  • startFromWorkflow - calling start() directly inside a workflow function with hook communication | wrun_01KX70GCFNSEJBFY57JN3TDXNN | 🔍 observability
  • fibonacciWorkflow - recursive workflow composition via start() | wrun_01KX70GECYE2Z94R6GERW0KXP9 | 🔍 observability
  • health check (queue-based) - workflow endpoint responds to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KX70GTZ0ZQZXGQ7C2BFJV6TQ | 🔍 observability
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KX70H04FW46YMWD6QG46XWER | 🔍 observability
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KX70H5APCQ5X10BDD2E9NEFP | 🔍 observability
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KX70HAED3MR1NQJD4K4AMKMA | 🔍 observability
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KX70HFS3S58EM4AE2880Q0X8 | 🔍 observability
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KX70HP1KX23WB6WFSD5D6EK4 | 🔍 observability
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KX70HV77BQ6HQD80F07MTVAG | 🔍 observability
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KX70J56HFQ7P7WXVNYV8MYZR | 🔍 observability
  • errorSubclassRoundTripWorkflow - first-class Error subclasses survive every serialization boundary | wrun_01KX70JBN07KH9A9GBRS3C5M1X | 🔍 observability
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KX70JE1XZCKS20KB28V5VXBS | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_01KX70JK549XBCFKTBK7Z9DE90 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_01KX70JQH8A34R25CK3FEYHMPQ | 🔍 observability
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep | wrun_01KX70JYGW020R0D3AWKVBQ8E7 | 🔍 observability
  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KX70K9FZ7XDD7PN1MEA1P673 | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KX70KHB7V394XPAWJB5EA0KG | 🔍 observability
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KX70KT90VT05T3TCEAQ3QHS8 | 🔍 observability
  • AbortController abortTimeoutWorkflow: timeout cancels long-running step
  • AbortController abortParallelWorkflow: abort cancels all parallel steps
  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step
  • AbortController abortAlreadyAbortedWorkflow: pre-aborted signal seen by step
  • AbortController abortReasonWorkflow: abort reason preserved across boundaries
  • AbortController abortAfterCompletionWorkflow: abort after step completes is a no-op
  • AbortController abortViaHookWorkflow: external hook triggers abort on in-flight step
  • AbortController abortExternalSignalWorkflow: signal passed as workflow input
  • AbortController abortExternalSignalInFlightWorkflow: external abort fires mid-flight, propagates to nested steps
  • AbortController abortAnyInWorkflowWorkflow: AbortSignal.any composes signals inside the workflow VM
  • AbortController abortAnyInStepWorkflow: AbortSignal.any inside a step composes deserialized signals
  • AbortController abortSurvivesReplayWorkflow: controller state consistent across replay
  • AbortController abortThrowIfAbortedWorkflow: throwIfAborted causes FatalError, no retries
  • AbortController abortReasonTypesWorkflow: various abort reason types propagate correctly
  • AbortController abortFetchUncaughtWorkflow: uncaught fetch AbortError is FatalError, no retries
  • AbortController abortFetchInFlightWorkflow: aborting cancels an in-flight fetch
  • AbortController abortVoidSleepTimeoutWorkflow: documented void sleep().then(abort) pattern works
  • AbortController abortDeterministicBranchWorkflow: if-check takes same path on first-run and replay
  • AbortController abortListenerWorkflow: signal.addEventListener fires on the deserialized step signal
  • AbortController abortThrowIfAbortedMidFlightWorkflow: throwIfAborted in a polling loop bails when abort fires
  • AbortController abortDeterministicBranchFromStepWorkflow: branches stay consistent when abort comes from a step
  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
  • AbortController abortHookOrderingWorkflow [hook-first-abort-first]: hook.then → addEventListener → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [hook-first-hook-first]: hook.then → addEventListener → resumeHook → abort()
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KX70QXN3XK19ABRCQWK95QCK | 🔍 observability
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KX70QZMD0PQMF78ZAAZ3E3EP | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KX70R1N4F715XE9R59M0R5H0 | 🔍 observability
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KX70R3KKEMTYJHBDBX3F8YD7 | 🔍 observability
  • distributedAbortController - manual abort triggers signal | wrun_01KX70R8QVZBYKG763KFC46FJT | 🔍 observability
  • distributedAbortController - TTL expiration triggers signal | wrun_01KX70RFAJ4YYSS80F2K95M1X3 | 🔍 observability
  • distributedAbortController - reconnect to existing controller | wrun_01KX70RNG7E3PCH7306DTBZ4TA | 🔍 observability
  • experimental_setAttributes start: initial attributes are seeded on run creation
  • experimental_setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • experimental_setAttributes experimentalSetAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • experimental_setAttributes experimentalSetAttributesInsideStepWorkflow: step-body calls append attributed native events
  • experimental_setAttributes fire-and-forget: void experimental_setAttributes lands without awaiting
  • experimental_setAttributes Promise.all of disjoint-key writes: every key lands
  • experimental_setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run
  • experimental_setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit
  • experimental_setAttributes start: invalid initial attributes are rejected before a run is created

nuxt (1 failed):

Details by Category

❌ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 126 0 29
✅ example 126 0 29
✅ express 126 0 29
✅ fastify 126 0 29
✅ hono 126 0 29
❌ nextjs-turbopack-bun 1 151 3
✅ nextjs-turbopack 151 0 4
✅ nextjs-webpack 150 0 5
✅ nitro 126 0 29
❌ nuxt 125 1 29
✅ sveltekit 145 0 10
✅ vite 126 0 29
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 128 0 27
✅ express-stable 128 0 27
✅ fastify-stable 128 0 27
✅ hono-stable 128 0 27
✅ nextjs-turbopack-canary 134 0 21
✅ nextjs-turbopack-stable 153 0 2
✅ nextjs-webpack-stable 153 0 2
✅ nitro-stable 128 0 27
✅ nuxt-stable 128 0 27
✅ sveltekit-stable 147 0 8
✅ vite-stable 128 0 27
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 128 0 27
✅ express-stable 128 0 27
✅ fastify-stable 128 0 27
✅ hono-stable 128 0 27
✅ nextjs-turbopack-canary 134 0 21
✅ nextjs-turbopack-stable 153 0 2
✅ nextjs-webpack-canary 134 0 21
✅ nextjs-webpack-stable 153 0 2
✅ nitro-stable 128 0 27
✅ nuxt-stable 128 0 27
✅ sveltekit-stable 147 0 8
✅ vite-stable 128 0 27
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 128 0 27
✅ express-stable 128 0 27
✅ fastify-stable 128 0 27
✅ hono-stable 128 0 27
✅ nextjs-turbopack-canary 134 0 21
✅ nextjs-turbopack-stable 153 0 2
✅ nextjs-webpack-canary 134 0 21
✅ nextjs-webpack-stable 153 0 2
✅ nitro-stable 128 0 27
✅ nuxt-stable 128 0 27
✅ sveltekit-stable 147 0 8
✅ vite-stable 128 0 27
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 153 0 2
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 128 0 27
✅ e2e-local-dev-tanstack-start- 128 0 27
✅ e2e-local-postgres-nest-stable 128 0 27
✅ e2e-local-postgres-tanstack-start- 128 0 27
✅ e2e-local-prod-nest-stable 128 0 27
✅ e2e-local-prod-tanstack-start- 128 0 27
✅ e2e-vercel-prod-tanstack-start 126 0 29

📋 View full workflow run


Some E2E test jobs failed:

  • Vercel Prod: failure
  • Local Dev: failure
  • Local Prod: success
  • Local Postgres: success
  • Windows: success

Check the workflow run for details.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

commit abe2892 · Fri, 10 Jul 2026 22:05:28 GMT · run logs

Backend: vercel · app: nextjs-turbopack

Metric Scenario Avg (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS stream 1470 (+40%) 1732 🔴 1783 🔴 1829 🔴 30
TTFS hook + stream 1479 (+15%) 1998 🔴 2043 🔴 2162 🔴 30
STSO 1020 steps (1-20) 261 (-1.4%) 319 🔴 372 🔴 488 🔴 19
STSO 1020 steps (101-120) 515 (+30%) 558 🔴 825 🔴 1300 🔴 19
STSO 1020 steps (1001-1020) 863 (-11%) 966 🔴 998 🔴 1027 🔴 19
WO stream 1470 (+40%) 1732 1783 1829 30
WO hook + stream 1479 (+15%) 1998 2043 2162 30
SL stream 4892 (+4.3%) 5147 🔴 5860 🔴 8557 🔴 30
SL hook + stream 5097 (+4.6%) 5666 🔴 5759 🔴 5816 🔴 30
📜 Previous results (3)

9d76b84

Fri, 10 Jul 2026 05:25:05 GMT · run logs

vercel / nextjs-turbopack

Metric Scenario Avg (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS stream 1171 (±0%) 1629 🔴 1643 🔴 1822 🔴 30
TTFS hook + stream 1266 (-8.0%) 1779 🔴 1838 🔴 1888 🔴 30
STSO 1020 steps (1-20) 273 (+0.6%) 319 🔴 410 🔴 453 🔴 19
STSO 1020 steps (101-120) 438 (+5.1%) 461 🔴 604 🔴 766 🔴 19
STSO 1020 steps (1001-1020) 874 (-19%) 942 🔴 1030 🔴 1323 🔴 19
WO stream 1171 (±0%) 1629 1643 1822 30
WO hook + stream 1266 (-8.0%) 1779 1838 1888 30
SL stream 4065 (-17%) 5061 🔴 5750 🔴 5969 🔴 30
SL hook + stream 5046 (±0%) 5563 🔴 5650 🔴 5788 🔴 30

1d96ca0

Fri, 10 Jul 2026 04:56:38 GMT · run logs

vercel / nextjs-turbopack

Metric Scenario Avg (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS stream 1300 (+11%) 1648 🔴 1761 🔴 1964 🔴 30
TTFS hook + stream 1702 (+24%) 1972 🔴 2064 🔴 2313 🔴 30
STSO 1020 steps (1-20) 316 (+16%) 378 🔴 447 🔴 654 🔴 19
STSO 1020 steps (101-120) 402 (-3.5%) 415 🔴 517 🔴 577 🔴 19
STSO 1020 steps (1001-1020) 1067 (-0.9%) 923 🔴 1001 🔴 5103 🔴 19
WO stream 1300 (+11%) 1648 1761 1964 30
WO hook + stream 1702 (+24%) 1972 2064 2313 30
SL stream 4816 (-2.2%) 5659 🔴 5717 🔴 5820 🔴 30
SL hook + stream 4824 (-4.0%) 4979 🔴 5743 🔴 5956 🔴 30

605b090

Thu, 09 Jul 2026 23:56:58 GMT · run logs

vercel / nextjs-turbopack

Metric Scenario Avg (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS stream 1141 (+2.6%) 1596 🔴 1685 🔴 2057 🔴 30
TTFS hook + stream 1451 (+13%) 1875 🔴 1986 🔴 2090 🔴 30
STSO 1020 steps (1-20) 260 (-4.6%) 304 🔴 342 🔴 348 🔴 19
STSO 1020 steps (101-120) 394 (-4.2%) 422 🔴 479 🔴 584 🔴 19
STSO 1020 steps (1001-1020) 992 (+14%) 925 🔴 1159 🔴 3384 🔴 19
WO stream 1141 (+2.6%) 1596 1685 2057 30
WO hook + stream 1451 (+13%) 1875 1986 2090 30
SL stream 4096 (-12%) 5680 🔴 5888 🔴 6142 🔴 30
SL hook + stream 5139 (+2.2%) 5743 🔴 5808 🔴 5890 🔴 30

Avg deltas compare against the most recent benchmark run on main at the time of this run.

Metrics — TTFS: time to first step body execution · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (time outside step bodies, client start → last step body exit) · SL: stream latency (first chunk write → visible to the reader)

Scenarios — stream: one step that streams chunks back to the client; no hooks, so the run stays in turbo mode · hook + stream: registers a hook before the same streaming step, which exits turbo mode · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges

🟢/🔴 mark percentiles within/above target. Targets (p75/p90/p99, ms) — TTFS 200/300/600 · SL 50/60/125 · STSO (1-20) 20/30/60 · STSO (101-120) 30/45/90 · STSO (1001-1020) 40/60/120

TTFS/WO compare client vs deployment clocks and SL compares the step runner’s clock vs the client’s (NTP-synced in CI). WO ends at the last step body exit, the closest observable proxy for the final step-completion request.

@NathanColosimo

Copy link
Copy Markdown
Contributor Author

Bun regression follow-up

Added focused coverage after the baseline run:

  • Bun runtime builtin and version (#393) imports the bun builtin from a step, asserts the runtime version, and records it in the E2E metadata artifact.
  • CBOR event replay with cumulative step I/O (#1735) mirrors the reported shape: roughly 2 KB of prepared output followed by 12 additional replaying steps. It runs on both Vercel Next.js/Turbopack lanes for a direct Node/Bun comparison.

Local production results:

The first CI run reached the Bun matrix job and waited the configured 1,000 seconds, then failed because no workbench-bun-workflow deployment status exists: https://github.com/vercel/workflow/actions/runs/29057841980/job/86253085237. This confirms the project Git-link/root-directory prerequisite in the PR description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant