[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[core] [world] Fix community world E2E tests broken by specVersion bump - #1658

Merged
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version
Apr 8, 2026
Merged

[core] [world] Fix community world E2E tests broken by specVersion bump#1658
VaguelySerious merged 3 commits into
mainfrom
peter/fix-community-world-spec-version

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

  • SPEC_VERSION_CURRENT was bumped to 3 in [core] [world] Gate CBOR queue transport on specVersion #1627, but community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects runs with specVersion 3, causing every workflow execution to return 500 and the E2E community world tests to time out after 30 minutes.
  • Reverts SPEC_VERSION_CURRENT to 2 (safe baseline all worlds handle) and adds a specVersion property to the World interface so individual world implementations can declare support for higher versions. world-vercel sets specVersion: 3, preserving CBOR queue transport and resilient start without breaking community worlds.

Test plan

  • All 581 core unit tests pass
  • All world-vercel tests pass (55 tests)
  • Typecheck passes across all affected packages
  • CI: E2E Community World (Redis) passes
  • CI: E2E Community World (MongoDB) passes
  • CI: E2E Community World (Turso) continues to pass
  • CI: E2E Vercel Prod Tests pass

🤖 Generated with Claude Code

…URRENT bump
SPEC_VERSION_CURRENT was bumped to 3 in #1627, but community worlds
(Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where
SPEC_VERSION_CURRENT is 2. Their requiresNewerWorld() check rejects
runs with specVersion 3, causing every workflow to 500 and the E2E
tests to time out.
Fix: revert SPEC_VERSION_CURRENT to 2 (safe baseline all worlds
handle) and add a `specVersion` property to the World interface so
individual worlds can declare support for higher versions.
world-vercel sets specVersion to 3, enabling CBOR queue transport
and resilient start without breaking community worlds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerApril 8, 2026 19:24
@vercel

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@changeset-bot

changeset-botBot commented Apr 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 67f2d9c

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

This PR includes changesets to release 20 packages
NameType
@workflow/corePatch
@workflow/worldPatch
@workflow/world-vercelPatch
@workflow/world-localPatch
@workflow/world-postgresPatch
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
workflowPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch
@workflow/nuxtPatch
@workflow/aiPatch

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

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

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production890067957
✅ 💻 Local Development86601781044
✅ 📦 Local Production86601781044
✅ 🐘 Local Postgres86601781044
✅ 🪟 Windows790887
❌ 🌍 Community Worlds1366524225
✅ 📋 Other219042261
Total3922656754662

❌ Failed Tests

🌍 Community Worlds (65 failed)

mongodb (4 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

redis (3 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2

turso (58 failed):

  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • addTenWorkflow | wrun_01KNQB4CPS7R10P413ZHRHGXDG
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNQB631R2CMT45B5R0Q24YA9
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNQB4KKQR7MSETCSFDFFHJAT
  • promiseRaceWorkflow | wrun_01KNQB4RPDF3FW0WQ40KWA0VWS
  • promiseAnyWorkflow | wrun_01KNQB4TKEMNKD5653RVJX93C5
  • importedStepOnlyWorkflow | wrun_01KNQB6DE2WZ26V6HE1CF1QNBS
  • hookWorkflow | wrun_01KNQB57JSMNRXJN0RADKD35D4
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNQB5HY10K0N9E31HQZJFFW0
  • webhookWorkflow | wrun_01KNQB5T5DXXE5BGYGBJ4HXKAJ
  • sleepingWorkflow | wrun_01KNQB60JHC4Y0BVG3QMF5C26F
  • parallelSleepWorkflow | wrun_01KNQB6CW6ZJEDEVGJ7DSEYRZB
  • nullByteWorkflow | wrun_01KNQB6G63S43XTP7JV586FKKE
  • workflowAndStepMetadataWorkflow | wrun_01KNQB6JFDXPP7F6Z2YSE3JAD4
  • fetchWorkflow | wrun_01KNQB97DM89EN2365JKM96E4X
  • promiseRaceStressTestWorkflow | wrun_01KNQB9AC6B0JPGSKPMCFQ5JW3
  • 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 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
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNQBCK3NXK2ENNTWEZBCS1K0
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNQBD5P032YVSKYAW2ACM2V6
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNQBDS4HMPW1CZREJ80E0YSA
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNQBEBKN48G65RGVFDPAK0QJ
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNQBEK3F6YPRW22TESZ8WXJW
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNQBEQR738JV2CH84YPCBR6F
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNQBET49TFEASJSD5YPDVJY4
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNQBFAXGSVQ7H2KNZQHTASZ9
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNQBFFQPXVY54QPF0QN2FD6D
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNQBFNCXGBT4CPN8RH91TZ0A
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNQBFV3CQ3A0BXSAX54HCDEN
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNQBG18FV09WYD40KZ1NMH8T
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNQBG83XX9BJKFMZPSE2K55A
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNQBGEZEFGA22NBYETZYV4VK
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNQBGRW77EWYT002MCJSPVFJ
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNQBH272S7FSFEACDE8PXC78
  • cancelRun - cancelling a running workflow | wrun_01KNQBH7XXXAB25HQ11JCE3XB4
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNQBHGA870FEX4575GC3Q7FN
  • 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_01KNQBHV9EN53V1H7YZK3T3GJT
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNQBJE0Y9V0CSKAZ8JG9JYG0
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNQBJS5VQRJRMN3A07PC6SVA
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNQBJZ0NNN233NS1F22C8X7R
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNQBK1WJNT2BA6E4RVRA35DN
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNQBK3M1EKRHKGK5JAZVGFF2
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNQBK71K3BG9X5GSZKWSN786

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro8007
✅ example8007
✅ express8007
✅ fastify8007
✅ hono8007
✅ nextjs-turbopack8502
✅ nextjs-webpack8502
✅ nitro8007
✅ nuxt8007
✅ sveltekit8007
✅ vite8007
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable73014
✅ express-stable73014
✅ fastify-stable73014
✅ hono-stable73014
✅ nextjs-turbopack-canary62025
✅ nextjs-turbopack-stable7908
✅ nextjs-webpack-canary62025
✅ nextjs-webpack-stable7908
✅ nitro-stable73014
✅ nuxt-stable73014
✅ sveltekit-stable73014
✅ vite-stable73014
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack7908
❌ 🌍 Community Worlds
AppPassedFailedSkipped
✅ mongodb-dev500
❌ mongodb5848
✅ redis-dev500
❌ redis5938
✅ turso-dev500
❌ turso4588
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable73014
✅ e2e-local-postgres-nest-stable73014
✅ e2e-local-prod-nest-stable73014

📋 View full workflow run

@github-actions

github-actionsBot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.041s (-3.3%)1.005s (~)0.964s101.00x
💻 LocalNitro0.041s (-6.8% 🟢)1.006s (~)0.964s101.02x
💻 LocalNext.js (Turbopack)0.048s1.005s0.957s101.19x
🌐 RedisNext.js (Turbopack)0.054s1.005s0.951s101.32x
🐘 PostgresExpress0.058s (+5.4% 🔺)1.010s (~)0.952s101.43x
🐘 PostgresNext.js (Turbopack)0.059s1.010s0.950s101.46x
🐘 PostgresNitro0.062s (+0.8%)1.011s (~)0.950s101.52x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)0.226s (-47.0% 🟢)2.487s (~)2.262s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)1.121s2.006s0.885s101.00x
🌐 RedisNext.js (Turbopack)1.126s2.006s0.881s101.00x
💻 LocalNitro1.129s (~)2.006s (~)0.877s101.01x
💻 LocalExpress1.130s (+0.6%)2.006s (~)0.876s101.01x
🐘 PostgresNext.js (Turbopack)1.139s2.011s0.873s101.02x
🐘 PostgresNitro1.142s (-0.6%)2.009s (~)0.867s101.02x
🐘 PostgresExpress1.144s (~)2.011s (~)0.867s101.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.076s (-0.8%)3.631s (-3.3%)1.555s101.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)10.775s11.023s0.248s31.00x
🌐 RedisNext.js (Turbopack)10.780s11.024s0.243s31.00x
🐘 PostgresNext.js (Turbopack)10.861s11.022s0.161s31.01x
🐘 PostgresNitro10.893s (~)11.022s (~)0.129s31.01x
💻 LocalNitro10.932s (-0.7%)11.023s (-3.0%)0.091s31.01x
🐘 PostgresExpress10.937s (~)11.024s (~)0.087s31.02x
💻 LocalExpress10.949s (~)11.024s (~)0.075s31.02x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)17.172s (~)19.107s (+1.3%)1.936s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)14.335s15.029s0.694s41.00x
🐘 PostgresNext.js (Turbopack)14.534s15.023s0.489s41.01x
🐘 PostgresNitro14.579s (~)15.021s (~)0.442s41.02x
💻 LocalNext.js (Turbopack)14.680s15.029s0.349s41.02x
🐘 PostgresExpress14.739s (+0.8%)15.023s (~)0.284s41.03x
💻 LocalNitro14.967s (-0.7%)15.029s (-4.8%)0.062s41.04x
💻 LocalExpress14.998s (~)15.278s (+1.7%)0.281s41.05x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)34.023s (+6.0% 🔺)36.073s (+7.0% 🔺)2.050s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)13.480s14.027s0.547s71.00x
🐘 PostgresNext.js (Turbopack)13.849s14.164s0.315s71.03x
🐘 PostgresNitro14.107s (~)14.881s (+1.0%)0.774s71.05x
🐘 PostgresExpress14.290s (+1.5%)15.020s (+1.0%)0.730s61.06x
💻 LocalNext.js (Turbopack)16.101s17.030s0.929s61.19x
💻 LocalExpress16.458s (~)17.031s (~)0.574s61.22x
💻 LocalNitro16.814s (-1.0%)17.032s (-1.9%)0.218s61.25x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)57.776s (-0.5%)59.408s (-1.6%)1.632s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.235s2.009s0.774s151.00x
🐘 PostgresExpress1.271s (+0.6%)2.010s (~)0.739s151.03x
🐘 PostgresNitro1.276s (~)2.011s (~)0.735s151.03x
🌐 RedisNext.js (Turbopack)1.306s2.006s0.700s151.06x
💻 LocalExpress1.492s (-4.2%)2.006s (-3.2%)0.514s151.21x
💻 LocalNext.js (Turbopack)1.517s2.006s0.489s151.23x
💻 LocalNitro1.569s (+1.0%)2.007s (~)0.438s151.27x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.250s (-6.7% 🟢)3.969s (-4.9%)1.719s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.347s (+0.6%)3.010s (~)0.664s101.00x
🐘 PostgresNitro2.359s (~)3.009s (~)0.649s101.01x
🐘 PostgresNext.js (Turbopack)2.461s3.010s0.549s101.05x
🌐 RedisNext.js (Turbopack)2.540s3.008s0.468s101.08x
💻 LocalNext.js (Turbopack)2.873s3.343s0.469s91.22x
💻 LocalExpress2.924s (+3.1%)3.109s (~)0.185s101.25x
💻 LocalNitro3.044s (-3.6%)3.885s (-3.2%)0.841s81.30x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.756s (~)4.314s (-12.2% 🟢)1.558s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.463s (~)4.012s (~)0.549s81.00x
🐘 PostgresNitro3.505s (+1.1%)4.014s (~)0.509s81.01x
🐘 PostgresNext.js (Turbopack)3.654s4.011s0.357s81.06x
🌐 RedisNext.js (Turbopack)4.255s5.011s0.756s61.23x
💻 LocalExpress7.545s (-6.8% 🟢)8.023s (-5.9% 🟢)0.479s42.18x
💻 LocalNitro8.261s (-7.7% 🟢)9.023s (-2.7%)0.761s42.39x
💻 LocalNext.js (Turbopack)8.978s9.272s0.295s42.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.766s (-3.9%)5.443s (-7.2% 🟢)1.676s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)1.223s2.008s0.786s151.00x
🐘 PostgresNitro1.263s (+0.9%)2.008s (~)0.744s151.03x
🐘 PostgresExpress1.268s (+1.5%)2.009s (~)0.741s151.04x
🌐 RedisNext.js (Turbopack)1.426s2.007s0.581s151.17x
💻 LocalExpress1.480s (-1.8%)2.005s (~)0.525s151.21x
💻 LocalNext.js (Turbopack)1.515s2.006s0.491s151.24x
💻 LocalNitro1.540s (-1.7%)2.007s (~)0.467s151.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.566s (+28.2% 🔺)4.188s (+14.1% 🔺)1.622s81.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express2.329s (~)3.008s (~)0.679s101.00x
🐘 PostgresNitro2.329s (-0.5%)3.010s (~)0.681s101.00x
🐘 PostgresNext.js (Turbopack)2.367s3.009s0.642s101.02x
🌐 RedisNext.js (Turbopack)2.592s3.008s0.417s101.11x
💻 LocalNext.js (Turbopack)2.740s3.342s0.602s91.18x
💻 LocalExpress2.943s (-16.6% 🟢)3.342s (-22.2% 🟢)0.399s91.26x
💻 LocalNitro3.161s (~)3.759s (-6.3% 🟢)0.599s81.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)2.705s (-7.0% 🟢)4.524s (-12.6% 🟢)1.819s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express3.485s (+0.9%)4.010s (~)0.525s81.00x
🐘 PostgresNitro3.496s (+1.1%)4.014s (~)0.518s81.00x
🐘 PostgresNext.js (Turbopack)3.659s4.013s0.353s81.05x
🌐 RedisNext.js (Turbopack)4.186s4.582s0.397s71.20x
💻 LocalExpress8.557s (-3.1%)9.023s (-2.7%)0.465s42.46x
💻 LocalNitro8.779s (-5.6% 🟢)9.273s (-7.5% 🟢)0.494s42.52x
💻 LocalNext.js (Turbopack)9.004s9.519s0.515s42.58x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.129s (-13.6% 🟢)4.846s (-12.7% 🟢)1.717s71.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.744s1.004s0.261s601.00x
🐘 PostgresNext.js (Turbopack)0.779s1.023s0.244s591.05x
🐘 PostgresNitro0.839s (-0.5%)1.006s (~)0.168s601.13x
💻 LocalNext.js (Turbopack)0.839s1.005s0.166s601.13x
🐘 PostgresExpress0.877s (-1.7%)1.040s (-1.8%)0.164s581.18x
💻 LocalNitro0.986s (-2.9%)1.158s (-35.7% 🟢)0.173s521.32x
💻 LocalExpress1.010s (+3.7%)1.584s (+42.0% 🔺)0.574s381.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)9.785s (-9.6% 🟢)11.625s (-7.9% 🟢)1.840s61.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.739s2.006s0.267s451.00x
🐘 PostgresNext.js (Turbopack)1.889s2.053s0.164s441.09x
🐘 PostgresNitro1.935s (-4.7%)2.123s (-24.7% 🟢)0.188s431.11x
🐘 PostgresExpress2.107s (+6.7% 🔺)2.976s (+28.6% 🔺)0.869s311.21x
💻 LocalNext.js (Turbopack)2.700s3.041s0.341s301.55x
💻 LocalExpress3.049s (+2.5%)3.800s (+16.7% 🔺)0.752s241.75x
💻 LocalNitro3.052s (-1.1%)3.801s (-5.2% 🟢)0.749s241.76x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)30.218s (+1.4%)32.174s (+2.0%)1.956s31.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)3.477s4.008s0.532s301.00x
🐘 PostgresNext.js (Turbopack)3.890s4.076s0.186s301.12x
🐘 PostgresNitro4.026s (-3.6%)4.566s (-8.9% 🟢)0.540s271.16x
🐘 PostgresExpress4.245s (+4.1%)5.012s (+7.5% 🔺)0.767s241.22x
💻 LocalNext.js (Turbopack)8.645s9.017s0.372s142.49x
💻 LocalExpress9.006s (-0.6%)9.478s (-0.8%)0.472s132.59x
💻 LocalNitro9.320s (-1.2%)10.019s (~)0.699s122.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)84.309s (+2.9%)86.009s (+2.1%)1.699s21.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.261s1.007s0.746s601.00x
🐘 PostgresExpress0.281s (+1.3%)1.007s (~)0.726s601.08x
🌐 RedisNext.js (Turbopack)0.288s1.004s0.716s601.11x
🐘 PostgresNitro0.290s (+1.7%)1.007s (~)0.717s601.11x
💻 LocalNext.js (Turbopack)0.545s1.004s0.460s602.09x
💻 LocalExpress0.580s (-2.7%)1.004s (~)0.424s602.22x
💻 LocalNitro0.598s (-4.0%)1.005s (-1.7%)0.407s602.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.828s (-7.0% 🟢)3.583s (-3.7%)1.754s181.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.478s1.006s0.529s901.00x
🐘 PostgresExpress0.484s (~)1.006s (~)0.522s901.01x
🐘 PostgresNitro0.504s (~)1.007s (~)0.503s901.05x
🌐 RedisNext.js (Turbopack)1.188s2.006s0.818s452.49x
💻 LocalExpress2.467s (-1.1%)3.009s (~)0.541s305.16x
💻 LocalNext.js (Turbopack)2.541s3.009s0.468s305.32x
💻 LocalNitro2.560s (-1.3%)3.009s (~)0.449s305.36x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.736s (+4.4%)5.431s (+3.0%)1.695s171.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Next.js (Turbopack)0.773s1.007s0.234s1201.00x
🐘 PostgresNitro0.807s (+0.8%)1.017s (~)0.210s1181.04x
🐘 PostgresExpress0.821s (+2.3%)1.009s (~)0.189s1191.06x
🌐 RedisNext.js (Turbopack)2.779s3.007s0.228s403.60x
💻 LocalNext.js (Turbopack)10.622s11.208s0.586s1113.74x
💻 LocalExpress10.785s (-2.3%)11.118s (-3.2%)0.334s1113.95x
💻 LocalNitro11.062s (-4.2%)11.847s (-1.5%)0.785s1114.31x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)6.913s (+0.9%)8.451s (~)1.538s151.00x
▲ VercelExpress⚠️missing----
▲ VercelNitro⚠️missing----

🔍 Observability: Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Next.js (Turbopack)0.167s1.003s0.012s1.018s0.851s101.00x
🌐 RedisNext.js (Turbopack)0.187s1.001s0.002s1.008s0.821s101.12x
🐘 PostgresNext.js (Turbopack)0.192s1.001s0.002s1.011s0.819s101.15x
💻 LocalExpress0.208s (+3.9%)1.004s (~)0.010s (-12.8% 🟢)1.016s (~)0.808s101.25x
💻 LocalNitro0.212s (-1.0%)1.005s (~)0.012s (-7.8% 🟢)1.019s (~)0.807s101.27x
🐘 PostgresNitro0.215s (+6.9% 🔺)0.995s (~)0.002s (-11.8% 🟢)1.012s (~)0.797s101.29x
🐘 PostgresExpress0.222s (+9.1% 🔺)0.996s (~)0.001s (~)1.010s (~)0.788s101.33x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)1.832s (-43.4% 🟢)3.075s (-36.9% 🟢)0.484s (+27.3% 🔺)4.005s (-29.3% 🟢)2.174s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.495s1.002s0.003s1.011s0.516s601.00x
🐘 PostgresNitro0.616s (~)1.004s (~)0.004s (~)1.022s (~)0.406s591.25x
🐘 PostgresNext.js (Turbopack)0.619s1.009s0.005s1.023s0.405s591.25x
🐘 PostgresExpress0.656s (~)1.005s (~)0.004s (-27.5% 🟢)1.025s (~)0.369s591.33x
💻 LocalNext.js (Turbopack)0.658s1.012s0.009s1.024s0.366s591.33x
💻 LocalNitro0.728s (-4.9%)1.011s (~)0.010s (+0.8%)1.023s (~)0.295s591.47x
💻 LocalExpress0.763s (-5.3% 🟢)1.012s (~)0.010s (-1.0%)1.024s (-8.2% 🟢)0.261s591.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)5.327s (+28.8% 🔺)6.427s (+9.7% 🔺)0.227s (-39.4% 🟢)7.162s (+6.4% 🔺)1.835s91.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)0.916s1.052s0.000s1.057s0.141s571.00x
🐘 PostgresNext.js (Turbopack)0.941s1.173s0.000s1.180s0.240s521.03x
🐘 PostgresExpress0.970s (+2.5%)1.169s (-4.2%)0.000s (+92.2% 🔺)1.186s (-3.8%)0.216s511.06x
🐘 PostgresNitro0.976s (+2.8%)1.220s (+4.8%)0.000s (-78.8% 🟢)1.232s (+4.1%)0.256s491.07x
💻 LocalNitro1.237s (-5.3% 🟢)2.022s (~)0.000s (-50.0% 🟢)2.024s (~)0.786s301.35x
💻 LocalNext.js (Turbopack)1.249s2.019s0.000s2.022s0.773s301.36x
💻 LocalExpress1.270s (-9.5% 🟢)2.024s (~)0.000s (+28.3% 🔺)2.026s (-7.9% 🟢)0.756s301.39x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)3.175s (-5.3% 🟢)4.517s (-8.1% 🟢)0.000s (-100.0% 🟢)4.938s (-8.0% 🟢)1.763s131.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🌐 Redis🥇 Next.js (Turbopack)1.705s2.035s0.000s2.039s0.335s301.00x
🐘 PostgresExpress1.764s (+1.2%)2.142s (+1.9%)0.000s (+55.4% 🔺)2.154s (+1.9%)0.390s281.03x
🐘 PostgresNitro1.824s (+4.2%)2.220s (+7.4% 🔺)0.000s (-46.3% 🟢)2.233s (+5.9% 🔺)0.409s271.07x
🐘 PostgresNext.js (Turbopack)1.920s2.181s0.000s2.189s0.269s281.13x
💻 LocalNitro3.499s (-6.2% 🟢)4.034s (-1.7%)0.001s (+71.4% 🔺)4.037s (-1.6%)0.538s152.05x
💻 LocalExpress3.514s (+2.5%)4.102s (+3.3%)0.001s (+86.7% 🔺)4.105s (+3.3%)0.591s152.06x
💻 LocalNext.js (Turbopack)3.700s4.233s0.001s4.237s0.537s152.17x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Next.js (Turbopack)113.360s (+2538.4% 🔺)114.539s (+1882.4% 🔺)0.000s (-100.0% 🟢)115.065s (+1728.4% 🔺)1.705s101.00x
▲ VercelExpress⚠️missing-----
▲ VercelNitro⚠️missing-----

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalNext.js (Turbopack)13/21
🐘 PostgresNext.js (Turbopack)14/21
▲ VercelNext.js (Turbopack)21/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres18/21
Next.js (Turbopack)🌐 Redis8/21
Nitro🐘 Postgres18/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

The previous approach (reverting to 2) broke E2E Local Dev/Prod/Postgres
tests because world-local also uses requiresNewerWorld() which rejects
specVersion > SPEC_VERSION_CURRENT.
Instead: keep SPEC_VERSION_CURRENT=3, add specVersion property to all
first-party worlds, and fall back to SPEC_VERSION_SUPPORTS_EVENT_SOURCING
(2) in start() when the world doesn't declare its version (community
worlds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good fix for the community world breakage. The approach is sound: add specVersion to the World interface so worlds can declare their capability, and have start() use that instead of the global SPEC_VERSION_CURRENT constant.

What I verified

The core problem: Community worlds (Redis, MongoDB) depend on @workflow/world v4.1.0-beta.2 where SPEC_VERSION_CURRENT = 2. Their requiresNewerWorld(3) check returns true and rejects runs, causing 500s.

The fix:start() fallback chain is now opts.specVersion > world.specVersion > SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). Community worlds don't set world.specVersion, so they get the safe baseline (2). Our worlds explicitly declare their version:

  • world-vercel: SPEC_VERSION_SUPPORTS_CBOR_QUEUE_TRANSPORT (3) — enables CBOR transport + resilient start
  • world-local: SPEC_VERSION_CURRENT (3)
  • world-postgres: SPEC_VERSION_CURRENT (3)

Health check specVersion: Both handleHealthCheckMessage and withHealthCheck now pass through worldSpecVersion from getWorldHandlers(), so the health check response reflects the actual world's version rather than the global constant. This is correct — the health check is used by the CLI to determine which queue transport to use (#1629).

Event-level SPEC_VERSION_CURRENT usage: The many SPEC_VERSION_CURRENT references in step-handler.ts, runtime.ts, suspension-handler.ts, etc. are for event specVersions created during runtime execution (not run creation). These are fine — by the time the code runs, the deployment has already started and the world is the local instance.

Clarification on PR description: The description says "Reverts SPEC_VERSION_CURRENT to 2" but the constant is NOT changed — it's still 3. The change is that start() no longer defaults to SPEC_VERSION_CURRENT when the world doesn't declare its version. The description should be updated to avoid confusion.

Non-blocking

  1. The World.specVersion JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, and the actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). The doc comment is misleading.

  2. world-local and world-postgres both set specVersion: SPEC_VERSION_CURRENT (3), which means they declare support for CBOR queue transport. This is fine since they don't use VQS and their queue implementations handle arbitrary payloads — but it's semantically a bit loose since CBOR transport is a VQS concept.

LGTM.

* features (e.g., CBOR queue transport) are enabled automatically.
* When omitted, runs default to `SPEC_VERSION_CURRENT` (the lowest
* version all worlds are expected to support).
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking: The JSDoc says "When omitted, runs default to SPEC_VERSION_CURRENT (the lowest version all worlds are expected to support)" — but SPEC_VERSION_CURRENT is 3, not 2. The actual fallback in start.ts is SPEC_VERSION_SUPPORTS_EVENT_SOURCING (2). This comment will confuse anyone reading the interface.

Suggested:

/** * The highest spec version this World supports. * * When set, `start()` creates runs at this version so world-specific * features (e.g., CBOR queue transport) are enabled automatically. * When omitted, runs default to `SPEC_VERSION_SUPPORTS_EVENT_SOURCING` (2), * the safe baseline that all worlds — including community worlds on * older @workflow/world versions — are expected to handle. */

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@VaguelySerious
VaguelySerious merged commit a5c90ce into mainApr 8, 2026
99 of 102 checks passed
@VaguelySerious
VaguelySerious deleted the peter/fix-community-world-spec-version branch April 8, 2026 20:15
@ghostghost mentioned this pull request Apr 8, 2026
@VaguelySeriousVaguelySerious added the backport-stable Cherry-pick this PR to the stable branch when merged label Apr 16, 2026
@ghost

Copy link
Copy Markdown

Backported to stable (a5c90ce -> 2ece7ba).

ghost pushed a commit that referenced this pull request Apr 16, 2026
…mp (#1658)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@ghost

Copy link
Copy Markdown

Backport to stable failed — the cherry-pick could not be applied cleanly.

To resolve manually:

git fetch origin stable
git checkout stable
git cherry-pick a5c90cefba01070aa4bc12a696334ee4c1061f92
# Fix conflicts, then:
git cherry-pick --continue
git push origin stable

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

Labels

backport-stableCherry-pick this PR to the stable branch when merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@VaguelySerious@TooTallNate