Skip to content

web: construct worlds explicitly instead of via static-injection stub - #2804

Merged
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection
Jul 7, 2026
Merged

web: construct worlds explicitly instead of via static-injection stub#2804
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection

Conversation

@karthikscale3

Copy link
Copy Markdown
Contributor

What changed

Fixes workflow web crashing for the local and postgres backends on latest main.

Since #2752, createWorld() from @workflow/core/runtime is a static-injection stub that throws unless a framework build plugin aliases @workflow/core/runtime/world-target to the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but @workflow/web's getWorldFromEnv still called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:

Workflow target world was not statically injected. Configure a Workflow builder/framework plugin so @workflow/core/runtime/world-target is aliased to the selected world package.

The Vercel backend was unaffected because that path constructs createVercelWorld directly.

Fix

Mirror the CLI's approach in getWorldFromEnv:

  • local / @workflow/world-local → import createWorld from @workflow/world-local directly (added as a dependency of @workflow/web)
  • any other backend id (e.g. @workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call its createWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installed

Repro / validation

  • Before: workflow web against a local-world project → every RPC returns the static-injection error.
  • After: rebuilt @workflow/web and verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).
  • pnpm exec vitest run app/server/workflow-server-actions.server.test.ts — 3/3 pass
  • tsc --noEmit on @workflow/web — 15 errors, identical to the pre-existing main baseline (zero new)

🤖 Generated with Claude Code

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).
Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3
karthikscale3 requested review from a team and ijjk as code ownersJuly 7, 2026 20:25
@changeset-bot

changeset-botBot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a42603f

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

This PR includes changesets to release 16 packages
NameType
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/web-sharedPatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

@vercel

vercelBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production144202301672
✅ 💻 Local Development145302191672
✅ 📦 Local Production160502191824
✅ 🐘 Local Postgres160502191824
✅ 🪟 Windows15200152
✅ 📋 Other88701771064
Total7144010648208

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro125027
✅ example125027
✅ express125027
✅ fastify125027
✅ hono125027
✅ nextjs-turbopack14903
✅ nextjs-webpack14903
✅ nitro125027
✅ nuxt125027
✅ sveltekit14408
✅ vite125027
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack15200
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable127025
✅ e2e-local-dev-tanstack-start-127025
✅ e2e-local-postgres-nest-stable127025
✅ e2e-local-postgres-tanstack-start-127025
✅ e2e-local-prod-nest-stable127025
✅ e2e-local-prod-tanstack-start-127025
✅ e2e-vercel-prod-tanstack-start125027

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented Jul 7, 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.047s (+4.9%)1.006s (~)0.959s101.00x
💻 LocalNitro0.048s (+3.2%)1.006s (~)0.958s101.02x
💻 LocalNext.js (Turbopack)0.056s (+6.0% 🔺)1.006s (~)0.950s101.20x
🐘 PostgresNitro0.063s (-3.7%)1.012s (~)0.949s101.35x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.219s (-2.8%)1.458s (-28.8% 🟢)1.239s101.00x
▲ VercelNitro0.487s (+159.0% 🔺)2.038s (~)1.551s102.23x
▲ VercelNext.js (Turbopack)0.635s (+161.2% 🔺)2.291s (-3.7%)1.656s102.90x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express1.089s (~)2.006s (~)0.916s101.00x
💻 LocalNitro1.091s (+1.2%)2.007s (~)0.915s101.00x
💻 LocalNext.js (Turbopack)1.093s (~)2.007s (~)0.914s101.00x
🐘 PostgresNitro1.095s (~)2.010s (~)0.915s101.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.442s (+5.9% 🔺)3.166s (+4.9%)1.724s101.00x
▲ VercelExpress1.474s (+4.0%)2.878s (+1.9%)1.403s101.02x
▲ VercelNext.js (Turbopack)2.324s (-0.9%)4.149s (+15.5% 🔺)1.825s101.61x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro10.467s (~)11.016s (~)0.549s31.00x
💻 LocalNitro10.494s (~)11.024s (~)0.530s31.00x
💻 LocalExpress10.514s (~)11.022s (~)0.508s31.00x
💻 LocalNext.js (Turbopack)10.527s (~)11.025s (~)0.497s31.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro11.727s (~)14.211s (+11.9% 🔺)2.484s31.00x
▲ VercelExpress12.164s (+4.2%)13.805s (-1.0%)1.642s31.04x
▲ VercelNext.js (Turbopack)13.328s (+3.1%)14.774s (+4.2%)1.446s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express13.611s (-0.6%)14.026s (~)0.415s51.00x
🐘 PostgresNitro13.614s (-0.7%)14.019s (~)0.405s51.00x
💻 LocalNitro13.635s (~)14.029s (~)0.394s51.00x
💻 LocalNext.js (Turbopack)13.937s (+1.6%)14.030s (~)0.093s51.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro16.424s (+1.5%)18.599s (+6.7% 🔺)2.175s41.00x
▲ VercelExpress16.637s (~)18.412s (-2.8%)1.775s41.01x
▲ VercelNext.js (Turbopack)18.769s (+4.5%)20.394s (+3.2%)1.625s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.110s (-1.8%)13.018s (~)0.908s71.00x
💻 LocalExpress12.259s (~)13.025s (~)0.766s71.01x
💻 LocalNitro12.334s (+0.9%)13.026s (~)0.693s71.02x
💻 LocalNext.js (Turbopack)12.987s (+6.1% 🔺)13.459s (+3.3%)0.472s71.07x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express18.067s (+4.5%)19.946s (+4.0%)1.880s51.00x
▲ VercelNitro19.085s (+11.7% 🔺)20.914s (+11.4% 🔺)1.828s51.06x
▲ VercelNext.js (Turbopack)23.005s (+16.7% 🔺)24.524s (+13.1% 🔺)1.519s41.27x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.202s (+1.3%)2.008s (~)0.806s151.00x
💻 LocalExpress1.414s (-2.1%)2.007s (~)0.593s151.18x
💻 LocalNitro1.425s (+1.3%)2.007s (~)0.582s151.19x
💻 LocalNext.js (Turbopack)1.458s (+3.6%)2.007s (~)0.549s151.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.058s (-10.0% 🟢)4.046s (+12.3% 🔺)1.987s81.00x
▲ VercelExpress2.129s (-6.3% 🟢)3.832s (-1.8%)1.704s81.03x
▲ VercelNext.js (Turbopack)3.677s (+25.2% 🔺)5.040s (+8.6% 🔺)1.363s61.79x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.309s (-6.4% 🟢)2.222s (-10.1% 🟢)0.913s141.00x
💻 LocalNitro2.389s (+3.0%)3.009s (~)0.620s101.82x
💻 LocalNext.js (Turbopack)2.473s (-0.6%)3.010s (-3.2%)0.537s101.89x
💻 LocalExpress2.491s (-6.2% 🟢)3.009s (-3.2%)0.517s101.90x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.366s (-6.4% 🟢)4.064s (+14.2% 🔺)1.698s81.00x
▲ VercelExpress2.432s (-6.7% 🟢)4.074s (-1.1%)1.642s81.03x
▲ VercelNext.js (Turbopack)4.373s (+31.4% 🔺)5.955s (+21.3% 🔺)1.582s61.85x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.542s (-5.3% 🟢)4.136s (~)2.594s81.00x
💻 LocalNext.js (Turbopack)2.942s (-37.4% 🟢)4.442s (-19.4% 🟢)1.500s71.91x
💻 LocalNitro4.604s (+7.2% 🔺)5.515s (+13.2% 🔺)0.910s62.99x
💻 LocalExpress4.804s (+8.8% 🔺)5.345s (+3.2%)0.541s63.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.779s (-1.8%)4.829s (+7.1% 🔺)2.050s71.00x
▲ VercelExpress2.978s (+2.0%)4.815s (+9.6% 🔺)1.837s71.07x
▲ VercelNext.js (Turbopack)4.742s (+20.0% 🔺)6.242s (+8.1% 🔺)1.500s51.71x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.179s (-1.5%)2.008s (~)0.829s151.00x
💻 LocalNitro1.437s (+1.6%)2.007s (~)0.570s151.22x
💻 LocalExpress1.452s (~)2.007s (~)0.555s151.23x
💻 LocalNext.js (Turbopack)1.522s (+1.4%)2.008s (~)0.486s151.29x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.055s (+6.3% 🔺)3.862s (+5.7% 🔺)1.807s81.00x
▲ VercelNitro2.153s (+13.4% 🔺)3.930s (+17.5% 🔺)1.778s81.05x
▲ VercelNext.js (Turbopack)3.867s (+30.1% 🔺)5.350s (+13.7% 🔺)1.483s61.88x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.294s (-1.9%)2.316s (+15.4% 🔺)1.022s131.00x
💻 LocalNitro2.601s (+6.5% 🔺)3.010s (~)0.409s102.01x
💻 LocalExpress2.608s (+4.8%)3.110s (+3.4%)0.502s102.02x
💻 LocalNext.js (Turbopack)2.737s (-2.6%)3.009s (-10.0% 🟢)0.272s102.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.427s (-21.7% 🟢)4.164s (-9.0% 🟢)1.737s81.00x
▲ VercelNitro2.715s (+23.6% 🔺)4.460s (+27.2% 🔺)1.746s71.12x
▲ VercelNext.js (Turbopack)3.706s (+17.5% 🔺)5.007s (+10.3% 🔺)1.300s61.53x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.576s (-3.6%)4.011s (-6.7% 🟢)2.435s81.00x
💻 LocalExpress5.357s (+50.2% 🔺)6.214s (+24.0% 🔺)0.857s53.40x
💻 LocalNitro5.624s (+1.8%)6.015s (~)0.392s53.57x
💻 LocalNext.js (Turbopack)5.759s (+6.5% 🔺)6.418s (+6.8% 🔺)0.659s53.65x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.839s (+11.5% 🔺)4.916s (+29.2% 🔺)2.076s71.00x
▲ VercelExpress3.410s (+28.1% 🔺)5.027s (+13.3% 🔺)1.617s61.20x
▲ VercelNext.js (Turbopack)4.339s (-3.8%)6.148s (~)1.809s51.53x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.600s (~)1.041s (+1.7%)0.442s581.00x
💻 LocalNitro0.610s (+4.4%)1.005s (~)0.395s601.02x
💻 LocalExpress0.624s (+3.0%)1.022s (+1.7%)0.399s591.04x
💻 LocalNext.js (Turbopack)0.728s (+21.5% 🔺)1.023s (+1.8%)0.295s591.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.688s (+3.2%)4.312s (+7.5% 🔺)1.624s151.00x
▲ VercelExpress2.717s (+9.2% 🔺)4.414s (+11.2% 🔺)1.697s141.01x
▲ VercelNext.js (Turbopack)3.979s (-1.8%)5.460s (-3.5%)1.481s111.48x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.209s (-13.2% 🟢)2.008s (-1.1%)0.798s451.00x
💻 LocalExpress1.512s (+1.2%)2.006s (~)0.495s451.25x
💻 LocalNitro1.535s (+6.1% 🔺)2.006s (~)0.471s451.27x
💻 LocalNext.js (Turbopack)1.709s (+8.6% 🔺)2.007s (~)0.297s451.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.321s (+8.2% 🔺)8.024s (+8.7% 🔺)1.703s121.00x
▲ VercelExpress6.554s (+12.6% 🔺)8.335s (+11.4% 🔺)1.781s111.04x
▲ VercelNext.js (Turbopack)8.643s (+4.8%)10.042s (+4.7%)1.399s101.37x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.672s (-6.1% 🟢)3.192s (-0.8%)0.520s381.00x
💻 LocalExpress3.321s (~)4.009s (~)0.688s301.24x
💻 LocalNitro3.368s (+6.0% 🔺)4.043s (+2.5%)0.675s301.26x
💻 LocalNext.js (Turbopack)3.766s (+9.8% 🔺)4.144s (+3.4%)0.378s301.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.319s (+5.4% 🔺)14.027s (+1.4%)1.707s91.00x
▲ VercelNitro13.548s (+17.9% 🔺)15.518s (+20.0% 🔺)1.971s81.10x
▲ VercelNext.js (Turbopack)17.303s (+0.9%)18.740s (~)1.438s71.40x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.210s (-4.8%)1.006s (~)0.795s601.00x
💻 LocalNitro0.523s (+2.2%)1.005s (~)0.482s602.49x
💻 LocalExpress0.606s (+17.3% 🔺)1.039s (+3.4%)0.434s582.88x
💻 LocalNext.js (Turbopack)0.728s (+13.3% 🔺)1.022s (~)0.294s593.46x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.148s (+2.0%)2.715s (+3.3%)1.567s231.00x
▲ VercelNitro1.215s (+10.8% 🔺)2.857s (+19.0% 🔺)1.643s211.06x
▲ VercelNext.js (Turbopack)2.173s (+11.0% 🔺)3.410s (+1.5%)1.237s181.89x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.329s (-6.0% 🟢)1.006s (~)0.677s901.00x
💻 LocalNitro2.521s (~)3.043s (+1.1%)0.522s307.66x
💻 LocalExpress2.555s (+1.0%)3.044s (~)0.489s307.76x
💻 LocalNext.js (Turbopack)2.752s (~)3.077s (-2.2%)0.325s308.36x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.371s (-3.8%)2.931s (-3.9%)1.560s311.00x
▲ VercelNitro1.402s (+6.0% 🔺)2.882s (+15.8% 🔺)1.481s321.02x
▲ VercelNext.js (Turbopack)2.875s (+11.0% 🔺)4.427s (+9.0% 🔺)1.552s212.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.553s (-3.6%)1.160s (+7.7% 🔺)0.607s1041.00x
💻 LocalExpress5.138s (-14.1% 🟢)8.157s (-3.9%)3.019s159.29x
💻 LocalNitro5.141s (-12.2% 🟢)8.811s (+1.4%)3.671s149.30x
💻 LocalNext.js (Turbopack)6.644s (+3.3%)9.643s (+4.3%)2.999s1312.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.832s (+14.2% 🔺)3.682s (+1.2%)1.849s331.00x
▲ VercelNitro1.861s (+11.7% 🔺)3.866s (+9.2% 🔺)2.006s321.02x
▲ VercelNext.js (Turbopack)3.980s (-5.3% 🟢)5.511s (-3.8%)1.531s222.17x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.145s (-1.5%)2.000s (~)0.001s (-16.7% 🟢)2.011s (~)0.866s101.00x
💻 LocalNext.js (Turbopack)1.163s (+2.1%)1.963s (~)0.013s (+30.1% 🔺)2.022s (~)0.859s101.02x
💻 LocalExpress1.165s (~)2.004s (~)0.012s (+5.3% 🔺)2.019s (~)0.854s101.02x
💻 LocalNitro1.166s (+0.9%)2.005s (~)0.013s (+21.9% 🔺)2.021s (~)0.855s101.02x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.063s (+8.2% 🔺)3.682s (+24.3% 🔺)5.347s (+190.7% 🔺)9.559s (+83.1% 🔺)7.496s101.00x
▲ VercelExpress2.078s (+9.9% 🔺)3.546s (+9.5% 🔺)5.423s (+231.1% 🔺)9.486s (+77.4% 🔺)7.407s101.01x
▲ VercelNext.js (Turbopack)3.838s (+20.4% 🔺)4.391s (+25.5% 🔺)5.361s (+268.2% 🔺)10.975s (+70.5% 🔺)7.137s101.86x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.537s (-5.7% 🟢)2.004s (~)0.006s (+6.4% 🔺)2.027s (~)0.490s301.00x
💻 LocalNitro1.579s (~)2.009s (-1.5%)0.013s (-2.2%)2.026s (-1.6%)0.446s301.03x
💻 LocalExpress1.581s (~)2.039s (+1.4%)0.012s (+3.9%)2.059s (+1.7%)0.478s301.03x
💻 LocalNext.js (Turbopack)1.684s (+5.2% 🔺)1.967s (~)0.014s (+14.1% 🔺)2.030s (~)0.346s301.10x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro5.558s (-2.3%)7.654s (+16.1% 🔺)0.194s (-16.6% 🟢)8.385s (+13.1% 🔺)2.827s81.00x
▲ VercelExpress5.710s (+5.2% 🔺)7.460s (+5.8% 🔺)0.096s (-57.0% 🟢)8.025s (+3.2%)2.316s81.03x
▲ VercelNext.js (Turbopack)9.376s (-1.4%)10.558s (~)1.070s (+389.3% 🔺)12.346s (+6.9% 🔺)2.970s51.69x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.765s (-9.7% 🟢)1.044s (-7.0% 🟢)0.000s (+174.1% 🔺)1.060s (-7.2% 🟢)0.295s581.00x
💻 LocalExpress1.334s (-1.5%)1.949s (+1.6%)0.000s (+80.6% 🔺)1.952s (+1.6%)0.618s311.74x
💻 LocalNitro1.334s (-1.1%)1.982s (+1.7%)0.000s (+33.3% 🔺)1.985s (+1.7%)0.651s311.74x
💻 LocalNext.js (Turbopack)1.490s (+6.4% 🔺)1.975s (~)0.001s (-5.3% 🟢)2.018s (~)0.528s301.95x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.983s (-27.4% 🟢)5.018s (-4.5%)0.000s (+Infinity% 🔺)5.529s (-3.4%)2.546s111.00x
▲ VercelExpress3.326s (-36.4% 🟢)4.680s (-29.3% 🟢)0.000s (-100.0% 🟢)5.361s (-24.9% 🟢)2.035s121.11x
▲ VercelNext.js (Turbopack)4.895s (+8.8% 🔺)5.805s (+7.4% 🔺)0.000s (+Infinity% 🔺)6.619s (+7.2% 🔺)1.724s101.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

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

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.884s (+5.8% 🔺)2.606s (+7.8% 🔺)0.000s (NaN%)2.619s (+7.6% 🔺)0.735s231.00x
💻 LocalExpress3.280s (-1.2%)3.901s (~)0.001s (+500.0% 🔺)3.906s (~)0.625s161.74x
💻 LocalNitro3.288s (+1.4%)3.901s (~)0.001s (-20.0% 🟢)3.904s (~)0.616s161.75x
💻 LocalNext.js (Turbopack)3.901s (+12.8% 🔺)4.349s (+9.0% 🔺)0.001s (-18.1% 🟢)4.394s (+9.0% 🔺)0.493s142.07x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.575s (+5.2% 🔺)6.251s (+19.0% 🔺)0.000s (NaN%)6.807s (+20.2% 🔺)2.233s91.00x
▲ VercelExpress4.731s (+5.4% 🔺)6.054s (+6.3% 🔺)0.000s (NaN%)6.638s (+7.7% 🔺)1.907s101.03x
▲ VercelNext.js (Turbopack)7.108s (-3.4%)7.730s (-1.0%)0.000s (NaN%)8.799s (-1.6%)1.691s71.55x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress11/21
🐘 PostgresNitro21/21
▲ VercelNitro13/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express💻 Local15/21
Next.js (Turbopack)💻 Local19/21
Nitro🐘 Postgres19/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)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)
  • 🌐 Platformatic: Community world (local development)

📋 View full workflow run

@VaguelySeriousVaguelySerious 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.

workflow-web preview doesn't load runs on this PR, but did on #2752

@VaguelySerious

Copy link
Copy Markdown
Member

^ actually seems to have broken some other commit, ignore

@VaguelySeriousVaguelySerious 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.

It'd be nice if we could unify the logic here between CLI/web since it'll invariable create drift, but otherwise LGTM

@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.

Reviewed and validated the fix live. Approving.

Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.

Correctness checks:

  • The env dance holds together: ensureLocalWorldDataDirEnv() still runs before construction and before the WORKFLOW_*-derived cache key is computed, and @workflow/world-local's createWorld() reads WORKFLOW_LOCAL_DATA_DIR — so the arg-less createLocalWorld() call picks up the inspected project's data dir, matching the CLI.
  • The dynamic path is a faithful mirror of the CLI's createPostgresCliWorld() (createRequire(join(cwd, 'package.json')).resolve + import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI. @workflow/world-postgres is "type": "module", so the named createWorld export resolves without interop concerns.
  • No remaining call sites of the core stub in packages/web; @workflow/world-local properly added to dependencies with lockfile update; changeset present and accurate (patch).
  • 85/85 web tests pass locally.

CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.

Two non-blocking thoughts:

  1. For community worlds shipped as CJS, import()'s named-export detection depends on cjs-module-lexer; a mod.createWorld ?? mod.default?.createWorld fallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together.
  2. The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.

karthikscale3 added a commit that referenced this pull request Jul 7, 2026
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Addressed the review feedback:

@karthikscale3
karthikscale3 merged commit cdfac39 into mainJul 7, 2026
177 of 184 checks passed
@karthikscale3
karthikscale3 deleted the karthik/web-fix-local-world-static-injection branch July 7, 2026 22:47
karthikscale3 added a commit that referenced this pull request Jul 7, 2026
* cli: restore dynamic world loading for community backends
Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.
Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* cli: fall back to default.createWorld for CJS world packages
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update .changeset/cli-generic-world-backends.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for cdfac39 (AI decision).

This commit works around the static-injection createWorld() stub introduced on main by #2752. On stable, createWorld() in packages/core/src/runtime/world.ts is still the older dynamic-selection implementation that resolves worlds at runtime, so the bug being fixed does not exist there and applying this change would be unnecessary (and could regress the working behavior).

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

cdfac39e07e2d15c95f7ab9ff8d244b8677931bd

@github-actionsgithub-actionsBot mentioned this pull request Jul 7, 2026
VaguelySerious added a commit that referenced this pull request Jul 29, 2026
This reverts the static world-target injection and restores runtime
resolution of the world package from `WORKFLOW_TARGET_WORLD`.
Because 141 commits have landed on top of #2752, this is a surgical
revert rather than a mechanical one. Removed: the `world-target` modules
in core/builders/utils, the bundler aliases and `define`s wired through
next/nitro/nuxt/astro/sveltekit/rollup/nest, the
`@workflow/core/runtime/world-target` export, and the
pg-native/node-compat-banner helpers that only existed to support the
statically bundled world.
Kept (later work that builds on #2752):
- `createWorldFromModule` / `WorldFactoryModule` in core (used by
world-testing and the nitro dev handler)
- `world-init` / `world-init-stub` / `getWorldLazy` and their
registration of `getWorld` on globalThis, plus the #3001 isolated
route bundle regression test
- #2804 (web), #2806 (cli dynamic community backends), #3112 (world
factory alias removal), #2988 (nest vercel builder), #2925/#2908
(nitro), #2799 (sveltekit typescript stub is dropped with the
injection it existed for), next basePath support, and the windows /
canary test timeout tuning
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@karthikscale3@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
web: construct worlds explicitly instead of via static-injection stub by karthikscale3 · Pull Request #2804 · vercel/workflow · GitHub
Skip to content

web: construct worlds explicitly instead of via static-injection stub - #2804

Merged
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection
Jul 7, 2026
Merged

web: construct worlds explicitly instead of via static-injection stub#2804
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection

Conversation

@karthikscale3

Copy link
Copy Markdown
Contributor

What changed

Fixes workflow web crashing for the local and postgres backends on latest main.

Since #2752, createWorld() from @workflow/core/runtime is a static-injection stub that throws unless a framework build plugin aliases @workflow/core/runtime/world-target to the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but @workflow/web's getWorldFromEnv still called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:

Workflow target world was not statically injected. Configure a Workflow builder/framework plugin so @workflow/core/runtime/world-target is aliased to the selected world package.

The Vercel backend was unaffected because that path constructs createVercelWorld directly.

Fix

Mirror the CLI's approach in getWorldFromEnv:

  • local / @workflow/world-local → import createWorld from @workflow/world-local directly (added as a dependency of @workflow/web)
  • any other backend id (e.g. @workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call its createWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installed

Repro / validation

  • Before: workflow web against a local-world project → every RPC returns the static-injection error.
  • After: rebuilt @workflow/web and verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).
  • pnpm exec vitest run app/server/workflow-server-actions.server.test.ts — 3/3 pass
  • tsc --noEmit on @workflow/web — 15 errors, identical to the pre-existing main baseline (zero new)

🤖 Generated with Claude Code

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).
Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3
karthikscale3 requested review from a team and ijjk as code ownersJuly 7, 2026 20:25
@changeset-bot

changeset-botBot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a42603f

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

This PR includes changesets to release 16 packages
NameType
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/web-sharedPatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

@vercel

vercelBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production144202301672
✅ 💻 Local Development145302191672
✅ 📦 Local Production160502191824
✅ 🐘 Local Postgres160502191824
✅ 🪟 Windows15200152
✅ 📋 Other88701771064
Total7144010648208

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro125027
✅ example125027
✅ express125027
✅ fastify125027
✅ hono125027
✅ nextjs-turbopack14903
✅ nextjs-webpack14903
✅ nitro125027
✅ nuxt125027
✅ sveltekit14408
✅ vite125027
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack15200
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable127025
✅ e2e-local-dev-tanstack-start-127025
✅ e2e-local-postgres-nest-stable127025
✅ e2e-local-postgres-tanstack-start-127025
✅ e2e-local-prod-nest-stable127025
✅ e2e-local-prod-tanstack-start-127025
✅ e2e-vercel-prod-tanstack-start125027

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented Jul 7, 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.047s (+4.9%)1.006s (~)0.959s101.00x
💻 LocalNitro0.048s (+3.2%)1.006s (~)0.958s101.02x
💻 LocalNext.js (Turbopack)0.056s (+6.0% 🔺)1.006s (~)0.950s101.20x
🐘 PostgresNitro0.063s (-3.7%)1.012s (~)0.949s101.35x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.219s (-2.8%)1.458s (-28.8% 🟢)1.239s101.00x
▲ VercelNitro0.487s (+159.0% 🔺)2.038s (~)1.551s102.23x
▲ VercelNext.js (Turbopack)0.635s (+161.2% 🔺)2.291s (-3.7%)1.656s102.90x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express1.089s (~)2.006s (~)0.916s101.00x
💻 LocalNitro1.091s (+1.2%)2.007s (~)0.915s101.00x
💻 LocalNext.js (Turbopack)1.093s (~)2.007s (~)0.914s101.00x
🐘 PostgresNitro1.095s (~)2.010s (~)0.915s101.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.442s (+5.9% 🔺)3.166s (+4.9%)1.724s101.00x
▲ VercelExpress1.474s (+4.0%)2.878s (+1.9%)1.403s101.02x
▲ VercelNext.js (Turbopack)2.324s (-0.9%)4.149s (+15.5% 🔺)1.825s101.61x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro10.467s (~)11.016s (~)0.549s31.00x
💻 LocalNitro10.494s (~)11.024s (~)0.530s31.00x
💻 LocalExpress10.514s (~)11.022s (~)0.508s31.00x
💻 LocalNext.js (Turbopack)10.527s (~)11.025s (~)0.497s31.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro11.727s (~)14.211s (+11.9% 🔺)2.484s31.00x
▲ VercelExpress12.164s (+4.2%)13.805s (-1.0%)1.642s31.04x
▲ VercelNext.js (Turbopack)13.328s (+3.1%)14.774s (+4.2%)1.446s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express13.611s (-0.6%)14.026s (~)0.415s51.00x
🐘 PostgresNitro13.614s (-0.7%)14.019s (~)0.405s51.00x
💻 LocalNitro13.635s (~)14.029s (~)0.394s51.00x
💻 LocalNext.js (Turbopack)13.937s (+1.6%)14.030s (~)0.093s51.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro16.424s (+1.5%)18.599s (+6.7% 🔺)2.175s41.00x
▲ VercelExpress16.637s (~)18.412s (-2.8%)1.775s41.01x
▲ VercelNext.js (Turbopack)18.769s (+4.5%)20.394s (+3.2%)1.625s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.110s (-1.8%)13.018s (~)0.908s71.00x
💻 LocalExpress12.259s (~)13.025s (~)0.766s71.01x
💻 LocalNitro12.334s (+0.9%)13.026s (~)0.693s71.02x
💻 LocalNext.js (Turbopack)12.987s (+6.1% 🔺)13.459s (+3.3%)0.472s71.07x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express18.067s (+4.5%)19.946s (+4.0%)1.880s51.00x
▲ VercelNitro19.085s (+11.7% 🔺)20.914s (+11.4% 🔺)1.828s51.06x
▲ VercelNext.js (Turbopack)23.005s (+16.7% 🔺)24.524s (+13.1% 🔺)1.519s41.27x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.202s (+1.3%)2.008s (~)0.806s151.00x
💻 LocalExpress1.414s (-2.1%)2.007s (~)0.593s151.18x
💻 LocalNitro1.425s (+1.3%)2.007s (~)0.582s151.19x
💻 LocalNext.js (Turbopack)1.458s (+3.6%)2.007s (~)0.549s151.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.058s (-10.0% 🟢)4.046s (+12.3% 🔺)1.987s81.00x
▲ VercelExpress2.129s (-6.3% 🟢)3.832s (-1.8%)1.704s81.03x
▲ VercelNext.js (Turbopack)3.677s (+25.2% 🔺)5.040s (+8.6% 🔺)1.363s61.79x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.309s (-6.4% 🟢)2.222s (-10.1% 🟢)0.913s141.00x
💻 LocalNitro2.389s (+3.0%)3.009s (~)0.620s101.82x
💻 LocalNext.js (Turbopack)2.473s (-0.6%)3.010s (-3.2%)0.537s101.89x
💻 LocalExpress2.491s (-6.2% 🟢)3.009s (-3.2%)0.517s101.90x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.366s (-6.4% 🟢)4.064s (+14.2% 🔺)1.698s81.00x
▲ VercelExpress2.432s (-6.7% 🟢)4.074s (-1.1%)1.642s81.03x
▲ VercelNext.js (Turbopack)4.373s (+31.4% 🔺)5.955s (+21.3% 🔺)1.582s61.85x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.542s (-5.3% 🟢)4.136s (~)2.594s81.00x
💻 LocalNext.js (Turbopack)2.942s (-37.4% 🟢)4.442s (-19.4% 🟢)1.500s71.91x
💻 LocalNitro4.604s (+7.2% 🔺)5.515s (+13.2% 🔺)0.910s62.99x
💻 LocalExpress4.804s (+8.8% 🔺)5.345s (+3.2%)0.541s63.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.779s (-1.8%)4.829s (+7.1% 🔺)2.050s71.00x
▲ VercelExpress2.978s (+2.0%)4.815s (+9.6% 🔺)1.837s71.07x
▲ VercelNext.js (Turbopack)4.742s (+20.0% 🔺)6.242s (+8.1% 🔺)1.500s51.71x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.179s (-1.5%)2.008s (~)0.829s151.00x
💻 LocalNitro1.437s (+1.6%)2.007s (~)0.570s151.22x
💻 LocalExpress1.452s (~)2.007s (~)0.555s151.23x
💻 LocalNext.js (Turbopack)1.522s (+1.4%)2.008s (~)0.486s151.29x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.055s (+6.3% 🔺)3.862s (+5.7% 🔺)1.807s81.00x
▲ VercelNitro2.153s (+13.4% 🔺)3.930s (+17.5% 🔺)1.778s81.05x
▲ VercelNext.js (Turbopack)3.867s (+30.1% 🔺)5.350s (+13.7% 🔺)1.483s61.88x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.294s (-1.9%)2.316s (+15.4% 🔺)1.022s131.00x
💻 LocalNitro2.601s (+6.5% 🔺)3.010s (~)0.409s102.01x
💻 LocalExpress2.608s (+4.8%)3.110s (+3.4%)0.502s102.02x
💻 LocalNext.js (Turbopack)2.737s (-2.6%)3.009s (-10.0% 🟢)0.272s102.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.427s (-21.7% 🟢)4.164s (-9.0% 🟢)1.737s81.00x
▲ VercelNitro2.715s (+23.6% 🔺)4.460s (+27.2% 🔺)1.746s71.12x
▲ VercelNext.js (Turbopack)3.706s (+17.5% 🔺)5.007s (+10.3% 🔺)1.300s61.53x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.576s (-3.6%)4.011s (-6.7% 🟢)2.435s81.00x
💻 LocalExpress5.357s (+50.2% 🔺)6.214s (+24.0% 🔺)0.857s53.40x
💻 LocalNitro5.624s (+1.8%)6.015s (~)0.392s53.57x
💻 LocalNext.js (Turbopack)5.759s (+6.5% 🔺)6.418s (+6.8% 🔺)0.659s53.65x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.839s (+11.5% 🔺)4.916s (+29.2% 🔺)2.076s71.00x
▲ VercelExpress3.410s (+28.1% 🔺)5.027s (+13.3% 🔺)1.617s61.20x
▲ VercelNext.js (Turbopack)4.339s (-3.8%)6.148s (~)1.809s51.53x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.600s (~)1.041s (+1.7%)0.442s581.00x
💻 LocalNitro0.610s (+4.4%)1.005s (~)0.395s601.02x
💻 LocalExpress0.624s (+3.0%)1.022s (+1.7%)0.399s591.04x
💻 LocalNext.js (Turbopack)0.728s (+21.5% 🔺)1.023s (+1.8%)0.295s591.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.688s (+3.2%)4.312s (+7.5% 🔺)1.624s151.00x
▲ VercelExpress2.717s (+9.2% 🔺)4.414s (+11.2% 🔺)1.697s141.01x
▲ VercelNext.js (Turbopack)3.979s (-1.8%)5.460s (-3.5%)1.481s111.48x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.209s (-13.2% 🟢)2.008s (-1.1%)0.798s451.00x
💻 LocalExpress1.512s (+1.2%)2.006s (~)0.495s451.25x
💻 LocalNitro1.535s (+6.1% 🔺)2.006s (~)0.471s451.27x
💻 LocalNext.js (Turbopack)1.709s (+8.6% 🔺)2.007s (~)0.297s451.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.321s (+8.2% 🔺)8.024s (+8.7% 🔺)1.703s121.00x
▲ VercelExpress6.554s (+12.6% 🔺)8.335s (+11.4% 🔺)1.781s111.04x
▲ VercelNext.js (Turbopack)8.643s (+4.8%)10.042s (+4.7%)1.399s101.37x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.672s (-6.1% 🟢)3.192s (-0.8%)0.520s381.00x
💻 LocalExpress3.321s (~)4.009s (~)0.688s301.24x
💻 LocalNitro3.368s (+6.0% 🔺)4.043s (+2.5%)0.675s301.26x
💻 LocalNext.js (Turbopack)3.766s (+9.8% 🔺)4.144s (+3.4%)0.378s301.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.319s (+5.4% 🔺)14.027s (+1.4%)1.707s91.00x
▲ VercelNitro13.548s (+17.9% 🔺)15.518s (+20.0% 🔺)1.971s81.10x
▲ VercelNext.js (Turbopack)17.303s (+0.9%)18.740s (~)1.438s71.40x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.210s (-4.8%)1.006s (~)0.795s601.00x
💻 LocalNitro0.523s (+2.2%)1.005s (~)0.482s602.49x
💻 LocalExpress0.606s (+17.3% 🔺)1.039s (+3.4%)0.434s582.88x
💻 LocalNext.js (Turbopack)0.728s (+13.3% 🔺)1.022s (~)0.294s593.46x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.148s (+2.0%)2.715s (+3.3%)1.567s231.00x
▲ VercelNitro1.215s (+10.8% 🔺)2.857s (+19.0% 🔺)1.643s211.06x
▲ VercelNext.js (Turbopack)2.173s (+11.0% 🔺)3.410s (+1.5%)1.237s181.89x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.329s (-6.0% 🟢)1.006s (~)0.677s901.00x
💻 LocalNitro2.521s (~)3.043s (+1.1%)0.522s307.66x
💻 LocalExpress2.555s (+1.0%)3.044s (~)0.489s307.76x
💻 LocalNext.js (Turbopack)2.752s (~)3.077s (-2.2%)0.325s308.36x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.371s (-3.8%)2.931s (-3.9%)1.560s311.00x
▲ VercelNitro1.402s (+6.0% 🔺)2.882s (+15.8% 🔺)1.481s321.02x
▲ VercelNext.js (Turbopack)2.875s (+11.0% 🔺)4.427s (+9.0% 🔺)1.552s212.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.553s (-3.6%)1.160s (+7.7% 🔺)0.607s1041.00x
💻 LocalExpress5.138s (-14.1% 🟢)8.157s (-3.9%)3.019s159.29x
💻 LocalNitro5.141s (-12.2% 🟢)8.811s (+1.4%)3.671s149.30x
💻 LocalNext.js (Turbopack)6.644s (+3.3%)9.643s (+4.3%)2.999s1312.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.832s (+14.2% 🔺)3.682s (+1.2%)1.849s331.00x
▲ VercelNitro1.861s (+11.7% 🔺)3.866s (+9.2% 🔺)2.006s321.02x
▲ VercelNext.js (Turbopack)3.980s (-5.3% 🟢)5.511s (-3.8%)1.531s222.17x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.145s (-1.5%)2.000s (~)0.001s (-16.7% 🟢)2.011s (~)0.866s101.00x
💻 LocalNext.js (Turbopack)1.163s (+2.1%)1.963s (~)0.013s (+30.1% 🔺)2.022s (~)0.859s101.02x
💻 LocalExpress1.165s (~)2.004s (~)0.012s (+5.3% 🔺)2.019s (~)0.854s101.02x
💻 LocalNitro1.166s (+0.9%)2.005s (~)0.013s (+21.9% 🔺)2.021s (~)0.855s101.02x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.063s (+8.2% 🔺)3.682s (+24.3% 🔺)5.347s (+190.7% 🔺)9.559s (+83.1% 🔺)7.496s101.00x
▲ VercelExpress2.078s (+9.9% 🔺)3.546s (+9.5% 🔺)5.423s (+231.1% 🔺)9.486s (+77.4% 🔺)7.407s101.01x
▲ VercelNext.js (Turbopack)3.838s (+20.4% 🔺)4.391s (+25.5% 🔺)5.361s (+268.2% 🔺)10.975s (+70.5% 🔺)7.137s101.86x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.537s (-5.7% 🟢)2.004s (~)0.006s (+6.4% 🔺)2.027s (~)0.490s301.00x
💻 LocalNitro1.579s (~)2.009s (-1.5%)0.013s (-2.2%)2.026s (-1.6%)0.446s301.03x
💻 LocalExpress1.581s (~)2.039s (+1.4%)0.012s (+3.9%)2.059s (+1.7%)0.478s301.03x
💻 LocalNext.js (Turbopack)1.684s (+5.2% 🔺)1.967s (~)0.014s (+14.1% 🔺)2.030s (~)0.346s301.10x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro5.558s (-2.3%)7.654s (+16.1% 🔺)0.194s (-16.6% 🟢)8.385s (+13.1% 🔺)2.827s81.00x
▲ VercelExpress5.710s (+5.2% 🔺)7.460s (+5.8% 🔺)0.096s (-57.0% 🟢)8.025s (+3.2%)2.316s81.03x
▲ VercelNext.js (Turbopack)9.376s (-1.4%)10.558s (~)1.070s (+389.3% 🔺)12.346s (+6.9% 🔺)2.970s51.69x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.765s (-9.7% 🟢)1.044s (-7.0% 🟢)0.000s (+174.1% 🔺)1.060s (-7.2% 🟢)0.295s581.00x
💻 LocalExpress1.334s (-1.5%)1.949s (+1.6%)0.000s (+80.6% 🔺)1.952s (+1.6%)0.618s311.74x
💻 LocalNitro1.334s (-1.1%)1.982s (+1.7%)0.000s (+33.3% 🔺)1.985s (+1.7%)0.651s311.74x
💻 LocalNext.js (Turbopack)1.490s (+6.4% 🔺)1.975s (~)0.001s (-5.3% 🟢)2.018s (~)0.528s301.95x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.983s (-27.4% 🟢)5.018s (-4.5%)0.000s (+Infinity% 🔺)5.529s (-3.4%)2.546s111.00x
▲ VercelExpress3.326s (-36.4% 🟢)4.680s (-29.3% 🟢)0.000s (-100.0% 🟢)5.361s (-24.9% 🟢)2.035s121.11x
▲ VercelNext.js (Turbopack)4.895s (+8.8% 🔺)5.805s (+7.4% 🔺)0.000s (+Infinity% 🔺)6.619s (+7.2% 🔺)1.724s101.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

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

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.884s (+5.8% 🔺)2.606s (+7.8% 🔺)0.000s (NaN%)2.619s (+7.6% 🔺)0.735s231.00x
💻 LocalExpress3.280s (-1.2%)3.901s (~)0.001s (+500.0% 🔺)3.906s (~)0.625s161.74x
💻 LocalNitro3.288s (+1.4%)3.901s (~)0.001s (-20.0% 🟢)3.904s (~)0.616s161.75x
💻 LocalNext.js (Turbopack)3.901s (+12.8% 🔺)4.349s (+9.0% 🔺)0.001s (-18.1% 🟢)4.394s (+9.0% 🔺)0.493s142.07x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.575s (+5.2% 🔺)6.251s (+19.0% 🔺)0.000s (NaN%)6.807s (+20.2% 🔺)2.233s91.00x
▲ VercelExpress4.731s (+5.4% 🔺)6.054s (+6.3% 🔺)0.000s (NaN%)6.638s (+7.7% 🔺)1.907s101.03x
▲ VercelNext.js (Turbopack)7.108s (-3.4%)7.730s (-1.0%)0.000s (NaN%)8.799s (-1.6%)1.691s71.55x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress11/21
🐘 PostgresNitro21/21
▲ VercelNitro13/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express💻 Local15/21
Next.js (Turbopack)💻 Local19/21
Nitro🐘 Postgres19/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)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)
  • 🌐 Platformatic: Community world (local development)

📋 View full workflow run

@VaguelySeriousVaguelySerious 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.

workflow-web preview doesn't load runs on this PR, but did on #2752

@VaguelySerious

Copy link
Copy Markdown
Member

^ actually seems to have broken some other commit, ignore

@VaguelySeriousVaguelySerious 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.

It'd be nice if we could unify the logic here between CLI/web since it'll invariable create drift, but otherwise LGTM

@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.

Reviewed and validated the fix live. Approving.

Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.

Correctness checks:

  • The env dance holds together: ensureLocalWorldDataDirEnv() still runs before construction and before the WORKFLOW_*-derived cache key is computed, and @workflow/world-local's createWorld() reads WORKFLOW_LOCAL_DATA_DIR — so the arg-less createLocalWorld() call picks up the inspected project's data dir, matching the CLI.
  • The dynamic path is a faithful mirror of the CLI's createPostgresCliWorld() (createRequire(join(cwd, 'package.json')).resolve + import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI. @workflow/world-postgres is "type": "module", so the named createWorld export resolves without interop concerns.
  • No remaining call sites of the core stub in packages/web; @workflow/world-local properly added to dependencies with lockfile update; changeset present and accurate (patch).
  • 85/85 web tests pass locally.

CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.

Two non-blocking thoughts:

  1. For community worlds shipped as CJS, import()'s named-export detection depends on cjs-module-lexer; a mod.createWorld ?? mod.default?.createWorld fallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together.
  2. The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.

karthikscale3 added a commit that referenced this pull request Jul 7, 2026
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Addressed the review feedback:

@karthikscale3
karthikscale3 merged commit cdfac39 into mainJul 7, 2026
177 of 184 checks passed
@karthikscale3
karthikscale3 deleted the karthik/web-fix-local-world-static-injection branch July 7, 2026 22:47
karthikscale3 added a commit that referenced this pull request Jul 7, 2026
* cli: restore dynamic world loading for community backends
Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.
Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* cli: fall back to default.createWorld for CJS world packages
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update .changeset/cli-generic-world-backends.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for cdfac39 (AI decision).

This commit works around the static-injection createWorld() stub introduced on main by #2752. On stable, createWorld() in packages/core/src/runtime/world.ts is still the older dynamic-selection implementation that resolves worlds at runtime, so the bug being fixed does not exist there and applying this change would be unnecessary (and could regress the working behavior).

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

cdfac39e07e2d15c95f7ab9ff8d244b8677931bd

@github-actionsgithub-actionsBot mentioned this pull request Jul 7, 2026
VaguelySerious added a commit that referenced this pull request Jul 29, 2026
This reverts the static world-target injection and restores runtime
resolution of the world package from `WORKFLOW_TARGET_WORLD`.
Because 141 commits have landed on top of #2752, this is a surgical
revert rather than a mechanical one. Removed: the `world-target` modules
in core/builders/utils, the bundler aliases and `define`s wired through
next/nitro/nuxt/astro/sveltekit/rollup/nest, the
`@workflow/core/runtime/world-target` export, and the
pg-native/node-compat-banner helpers that only existed to support the
statically bundled world.
Kept (later work that builds on #2752):
- `createWorldFromModule` / `WorldFactoryModule` in core (used by
world-testing and the nitro dev handler)
- `world-init` / `world-init-stub` / `getWorldLazy` and their
registration of `getWorld` on globalThis, plus the #3001 isolated
route bundle regression test
- #2804 (web), #2806 (cli dynamic community backends), #3112 (world
factory alias removal), #2988 (nest vercel builder), #2925/#2908
(nitro), #2799 (sveltekit typescript stub is dropped with the
injection it existed for), next basePath support, and the windows /
canary test timeout tuning
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

web: construct worlds explicitly instead of via static-injection stub - #2804

Merged
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection
Jul 7, 2026
Merged

web: construct worlds explicitly instead of via static-injection stub#2804
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection

Conversation

@karthikscale3

Copy link
Copy Markdown
Contributor

What changed

Fixes workflow web crashing for the local and postgres backends on latest main.

Since #2752, createWorld() from @workflow/core/runtime is a static-injection stub that throws unless a framework build plugin aliases @workflow/core/runtime/world-target to the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but @workflow/web's getWorldFromEnv still called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:

Workflow target world was not statically injected. Configure a Workflow builder/framework plugin so @workflow/core/runtime/world-target is aliased to the selected world package.

The Vercel backend was unaffected because that path constructs createVercelWorld directly.

Fix

Mirror the CLI's approach in getWorldFromEnv:

  • local / @workflow/world-local → import createWorld from @workflow/world-local directly (added as a dependency of @workflow/web)
  • any other backend id (e.g. @workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call its createWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installed

Repro / validation

  • Before: workflow web against a local-world project → every RPC returns the static-injection error.
  • After: rebuilt @workflow/web and verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).
  • pnpm exec vitest run app/server/workflow-server-actions.server.test.ts — 3/3 pass
  • tsc --noEmit on @workflow/web — 15 errors, identical to the pre-existing main baseline (zero new)

🤖 Generated with Claude Code

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).
Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3
karthikscale3 requested review from a team and ijjk as code ownersJuly 7, 2026 20:25
@changeset-bot

changeset-botBot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a42603f

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

This PR includes changesets to release 16 packages
NameType
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/web-sharedPatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

@vercel

vercelBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production144202301672
✅ 💻 Local Development145302191672
✅ 📦 Local Production160502191824
✅ 🐘 Local Postgres160502191824
✅ 🪟 Windows15200152
✅ 📋 Other88701771064
Total7144010648208

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro125027
✅ example125027
✅ express125027
✅ fastify125027
✅ hono125027
✅ nextjs-turbopack14903
✅ nextjs-webpack14903
✅ nitro125027
✅ nuxt125027
✅ sveltekit14408
✅ vite125027
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack15200
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable127025
✅ e2e-local-dev-tanstack-start-127025
✅ e2e-local-postgres-nest-stable127025
✅ e2e-local-postgres-tanstack-start-127025
✅ e2e-local-prod-nest-stable127025
✅ e2e-local-prod-tanstack-start-127025
✅ e2e-vercel-prod-tanstack-start125027

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented Jul 7, 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.047s (+4.9%)1.006s (~)0.959s101.00x
💻 LocalNitro0.048s (+3.2%)1.006s (~)0.958s101.02x
💻 LocalNext.js (Turbopack)0.056s (+6.0% 🔺)1.006s (~)0.950s101.20x
🐘 PostgresNitro0.063s (-3.7%)1.012s (~)0.949s101.35x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.219s (-2.8%)1.458s (-28.8% 🟢)1.239s101.00x
▲ VercelNitro0.487s (+159.0% 🔺)2.038s (~)1.551s102.23x
▲ VercelNext.js (Turbopack)0.635s (+161.2% 🔺)2.291s (-3.7%)1.656s102.90x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express1.089s (~)2.006s (~)0.916s101.00x
💻 LocalNitro1.091s (+1.2%)2.007s (~)0.915s101.00x
💻 LocalNext.js (Turbopack)1.093s (~)2.007s (~)0.914s101.00x
🐘 PostgresNitro1.095s (~)2.010s (~)0.915s101.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.442s (+5.9% 🔺)3.166s (+4.9%)1.724s101.00x
▲ VercelExpress1.474s (+4.0%)2.878s (+1.9%)1.403s101.02x
▲ VercelNext.js (Turbopack)2.324s (-0.9%)4.149s (+15.5% 🔺)1.825s101.61x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro10.467s (~)11.016s (~)0.549s31.00x
💻 LocalNitro10.494s (~)11.024s (~)0.530s31.00x
💻 LocalExpress10.514s (~)11.022s (~)0.508s31.00x
💻 LocalNext.js (Turbopack)10.527s (~)11.025s (~)0.497s31.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro11.727s (~)14.211s (+11.9% 🔺)2.484s31.00x
▲ VercelExpress12.164s (+4.2%)13.805s (-1.0%)1.642s31.04x
▲ VercelNext.js (Turbopack)13.328s (+3.1%)14.774s (+4.2%)1.446s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express13.611s (-0.6%)14.026s (~)0.415s51.00x
🐘 PostgresNitro13.614s (-0.7%)14.019s (~)0.405s51.00x
💻 LocalNitro13.635s (~)14.029s (~)0.394s51.00x
💻 LocalNext.js (Turbopack)13.937s (+1.6%)14.030s (~)0.093s51.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro16.424s (+1.5%)18.599s (+6.7% 🔺)2.175s41.00x
▲ VercelExpress16.637s (~)18.412s (-2.8%)1.775s41.01x
▲ VercelNext.js (Turbopack)18.769s (+4.5%)20.394s (+3.2%)1.625s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.110s (-1.8%)13.018s (~)0.908s71.00x
💻 LocalExpress12.259s (~)13.025s (~)0.766s71.01x
💻 LocalNitro12.334s (+0.9%)13.026s (~)0.693s71.02x
💻 LocalNext.js (Turbopack)12.987s (+6.1% 🔺)13.459s (+3.3%)0.472s71.07x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express18.067s (+4.5%)19.946s (+4.0%)1.880s51.00x
▲ VercelNitro19.085s (+11.7% 🔺)20.914s (+11.4% 🔺)1.828s51.06x
▲ VercelNext.js (Turbopack)23.005s (+16.7% 🔺)24.524s (+13.1% 🔺)1.519s41.27x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.202s (+1.3%)2.008s (~)0.806s151.00x
💻 LocalExpress1.414s (-2.1%)2.007s (~)0.593s151.18x
💻 LocalNitro1.425s (+1.3%)2.007s (~)0.582s151.19x
💻 LocalNext.js (Turbopack)1.458s (+3.6%)2.007s (~)0.549s151.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.058s (-10.0% 🟢)4.046s (+12.3% 🔺)1.987s81.00x
▲ VercelExpress2.129s (-6.3% 🟢)3.832s (-1.8%)1.704s81.03x
▲ VercelNext.js (Turbopack)3.677s (+25.2% 🔺)5.040s (+8.6% 🔺)1.363s61.79x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.309s (-6.4% 🟢)2.222s (-10.1% 🟢)0.913s141.00x
💻 LocalNitro2.389s (+3.0%)3.009s (~)0.620s101.82x
💻 LocalNext.js (Turbopack)2.473s (-0.6%)3.010s (-3.2%)0.537s101.89x
💻 LocalExpress2.491s (-6.2% 🟢)3.009s (-3.2%)0.517s101.90x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.366s (-6.4% 🟢)4.064s (+14.2% 🔺)1.698s81.00x
▲ VercelExpress2.432s (-6.7% 🟢)4.074s (-1.1%)1.642s81.03x
▲ VercelNext.js (Turbopack)4.373s (+31.4% 🔺)5.955s (+21.3% 🔺)1.582s61.85x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.542s (-5.3% 🟢)4.136s (~)2.594s81.00x
💻 LocalNext.js (Turbopack)2.942s (-37.4% 🟢)4.442s (-19.4% 🟢)1.500s71.91x
💻 LocalNitro4.604s (+7.2% 🔺)5.515s (+13.2% 🔺)0.910s62.99x
💻 LocalExpress4.804s (+8.8% 🔺)5.345s (+3.2%)0.541s63.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.779s (-1.8%)4.829s (+7.1% 🔺)2.050s71.00x
▲ VercelExpress2.978s (+2.0%)4.815s (+9.6% 🔺)1.837s71.07x
▲ VercelNext.js (Turbopack)4.742s (+20.0% 🔺)6.242s (+8.1% 🔺)1.500s51.71x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.179s (-1.5%)2.008s (~)0.829s151.00x
💻 LocalNitro1.437s (+1.6%)2.007s (~)0.570s151.22x
💻 LocalExpress1.452s (~)2.007s (~)0.555s151.23x
💻 LocalNext.js (Turbopack)1.522s (+1.4%)2.008s (~)0.486s151.29x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.055s (+6.3% 🔺)3.862s (+5.7% 🔺)1.807s81.00x
▲ VercelNitro2.153s (+13.4% 🔺)3.930s (+17.5% 🔺)1.778s81.05x
▲ VercelNext.js (Turbopack)3.867s (+30.1% 🔺)5.350s (+13.7% 🔺)1.483s61.88x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.294s (-1.9%)2.316s (+15.4% 🔺)1.022s131.00x
💻 LocalNitro2.601s (+6.5% 🔺)3.010s (~)0.409s102.01x
💻 LocalExpress2.608s (+4.8%)3.110s (+3.4%)0.502s102.02x
💻 LocalNext.js (Turbopack)2.737s (-2.6%)3.009s (-10.0% 🟢)0.272s102.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.427s (-21.7% 🟢)4.164s (-9.0% 🟢)1.737s81.00x
▲ VercelNitro2.715s (+23.6% 🔺)4.460s (+27.2% 🔺)1.746s71.12x
▲ VercelNext.js (Turbopack)3.706s (+17.5% 🔺)5.007s (+10.3% 🔺)1.300s61.53x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.576s (-3.6%)4.011s (-6.7% 🟢)2.435s81.00x
💻 LocalExpress5.357s (+50.2% 🔺)6.214s (+24.0% 🔺)0.857s53.40x
💻 LocalNitro5.624s (+1.8%)6.015s (~)0.392s53.57x
💻 LocalNext.js (Turbopack)5.759s (+6.5% 🔺)6.418s (+6.8% 🔺)0.659s53.65x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.839s (+11.5% 🔺)4.916s (+29.2% 🔺)2.076s71.00x
▲ VercelExpress3.410s (+28.1% 🔺)5.027s (+13.3% 🔺)1.617s61.20x
▲ VercelNext.js (Turbopack)4.339s (-3.8%)6.148s (~)1.809s51.53x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.600s (~)1.041s (+1.7%)0.442s581.00x
💻 LocalNitro0.610s (+4.4%)1.005s (~)0.395s601.02x
💻 LocalExpress0.624s (+3.0%)1.022s (+1.7%)0.399s591.04x
💻 LocalNext.js (Turbopack)0.728s (+21.5% 🔺)1.023s (+1.8%)0.295s591.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.688s (+3.2%)4.312s (+7.5% 🔺)1.624s151.00x
▲ VercelExpress2.717s (+9.2% 🔺)4.414s (+11.2% 🔺)1.697s141.01x
▲ VercelNext.js (Turbopack)3.979s (-1.8%)5.460s (-3.5%)1.481s111.48x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.209s (-13.2% 🟢)2.008s (-1.1%)0.798s451.00x
💻 LocalExpress1.512s (+1.2%)2.006s (~)0.495s451.25x
💻 LocalNitro1.535s (+6.1% 🔺)2.006s (~)0.471s451.27x
💻 LocalNext.js (Turbopack)1.709s (+8.6% 🔺)2.007s (~)0.297s451.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.321s (+8.2% 🔺)8.024s (+8.7% 🔺)1.703s121.00x
▲ VercelExpress6.554s (+12.6% 🔺)8.335s (+11.4% 🔺)1.781s111.04x
▲ VercelNext.js (Turbopack)8.643s (+4.8%)10.042s (+4.7%)1.399s101.37x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.672s (-6.1% 🟢)3.192s (-0.8%)0.520s381.00x
💻 LocalExpress3.321s (~)4.009s (~)0.688s301.24x
💻 LocalNitro3.368s (+6.0% 🔺)4.043s (+2.5%)0.675s301.26x
💻 LocalNext.js (Turbopack)3.766s (+9.8% 🔺)4.144s (+3.4%)0.378s301.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.319s (+5.4% 🔺)14.027s (+1.4%)1.707s91.00x
▲ VercelNitro13.548s (+17.9% 🔺)15.518s (+20.0% 🔺)1.971s81.10x
▲ VercelNext.js (Turbopack)17.303s (+0.9%)18.740s (~)1.438s71.40x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.210s (-4.8%)1.006s (~)0.795s601.00x
💻 LocalNitro0.523s (+2.2%)1.005s (~)0.482s602.49x
💻 LocalExpress0.606s (+17.3% 🔺)1.039s (+3.4%)0.434s582.88x
💻 LocalNext.js (Turbopack)0.728s (+13.3% 🔺)1.022s (~)0.294s593.46x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.148s (+2.0%)2.715s (+3.3%)1.567s231.00x
▲ VercelNitro1.215s (+10.8% 🔺)2.857s (+19.0% 🔺)1.643s211.06x
▲ VercelNext.js (Turbopack)2.173s (+11.0% 🔺)3.410s (+1.5%)1.237s181.89x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.329s (-6.0% 🟢)1.006s (~)0.677s901.00x
💻 LocalNitro2.521s (~)3.043s (+1.1%)0.522s307.66x
💻 LocalExpress2.555s (+1.0%)3.044s (~)0.489s307.76x
💻 LocalNext.js (Turbopack)2.752s (~)3.077s (-2.2%)0.325s308.36x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.371s (-3.8%)2.931s (-3.9%)1.560s311.00x
▲ VercelNitro1.402s (+6.0% 🔺)2.882s (+15.8% 🔺)1.481s321.02x
▲ VercelNext.js (Turbopack)2.875s (+11.0% 🔺)4.427s (+9.0% 🔺)1.552s212.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.553s (-3.6%)1.160s (+7.7% 🔺)0.607s1041.00x
💻 LocalExpress5.138s (-14.1% 🟢)8.157s (-3.9%)3.019s159.29x
💻 LocalNitro5.141s (-12.2% 🟢)8.811s (+1.4%)3.671s149.30x
💻 LocalNext.js (Turbopack)6.644s (+3.3%)9.643s (+4.3%)2.999s1312.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.832s (+14.2% 🔺)3.682s (+1.2%)1.849s331.00x
▲ VercelNitro1.861s (+11.7% 🔺)3.866s (+9.2% 🔺)2.006s321.02x
▲ VercelNext.js (Turbopack)3.980s (-5.3% 🟢)5.511s (-3.8%)1.531s222.17x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.145s (-1.5%)2.000s (~)0.001s (-16.7% 🟢)2.011s (~)0.866s101.00x
💻 LocalNext.js (Turbopack)1.163s (+2.1%)1.963s (~)0.013s (+30.1% 🔺)2.022s (~)0.859s101.02x
💻 LocalExpress1.165s (~)2.004s (~)0.012s (+5.3% 🔺)2.019s (~)0.854s101.02x
💻 LocalNitro1.166s (+0.9%)2.005s (~)0.013s (+21.9% 🔺)2.021s (~)0.855s101.02x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.063s (+8.2% 🔺)3.682s (+24.3% 🔺)5.347s (+190.7% 🔺)9.559s (+83.1% 🔺)7.496s101.00x
▲ VercelExpress2.078s (+9.9% 🔺)3.546s (+9.5% 🔺)5.423s (+231.1% 🔺)9.486s (+77.4% 🔺)7.407s101.01x
▲ VercelNext.js (Turbopack)3.838s (+20.4% 🔺)4.391s (+25.5% 🔺)5.361s (+268.2% 🔺)10.975s (+70.5% 🔺)7.137s101.86x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.537s (-5.7% 🟢)2.004s (~)0.006s (+6.4% 🔺)2.027s (~)0.490s301.00x
💻 LocalNitro1.579s (~)2.009s (-1.5%)0.013s (-2.2%)2.026s (-1.6%)0.446s301.03x
💻 LocalExpress1.581s (~)2.039s (+1.4%)0.012s (+3.9%)2.059s (+1.7%)0.478s301.03x
💻 LocalNext.js (Turbopack)1.684s (+5.2% 🔺)1.967s (~)0.014s (+14.1% 🔺)2.030s (~)0.346s301.10x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro5.558s (-2.3%)7.654s (+16.1% 🔺)0.194s (-16.6% 🟢)8.385s (+13.1% 🔺)2.827s81.00x
▲ VercelExpress5.710s (+5.2% 🔺)7.460s (+5.8% 🔺)0.096s (-57.0% 🟢)8.025s (+3.2%)2.316s81.03x
▲ VercelNext.js (Turbopack)9.376s (-1.4%)10.558s (~)1.070s (+389.3% 🔺)12.346s (+6.9% 🔺)2.970s51.69x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.765s (-9.7% 🟢)1.044s (-7.0% 🟢)0.000s (+174.1% 🔺)1.060s (-7.2% 🟢)0.295s581.00x
💻 LocalExpress1.334s (-1.5%)1.949s (+1.6%)0.000s (+80.6% 🔺)1.952s (+1.6%)0.618s311.74x
💻 LocalNitro1.334s (-1.1%)1.982s (+1.7%)0.000s (+33.3% 🔺)1.985s (+1.7%)0.651s311.74x
💻 LocalNext.js (Turbopack)1.490s (+6.4% 🔺)1.975s (~)0.001s (-5.3% 🟢)2.018s (~)0.528s301.95x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.983s (-27.4% 🟢)5.018s (-4.5%)0.000s (+Infinity% 🔺)5.529s (-3.4%)2.546s111.00x
▲ VercelExpress3.326s (-36.4% 🟢)4.680s (-29.3% 🟢)0.000s (-100.0% 🟢)5.361s (-24.9% 🟢)2.035s121.11x
▲ VercelNext.js (Turbopack)4.895s (+8.8% 🔺)5.805s (+7.4% 🔺)0.000s (+Infinity% 🔺)6.619s (+7.2% 🔺)1.724s101.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

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

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.884s (+5.8% 🔺)2.606s (+7.8% 🔺)0.000s (NaN%)2.619s (+7.6% 🔺)0.735s231.00x
💻 LocalExpress3.280s (-1.2%)3.901s (~)0.001s (+500.0% 🔺)3.906s (~)0.625s161.74x
💻 LocalNitro3.288s (+1.4%)3.901s (~)0.001s (-20.0% 🟢)3.904s (~)0.616s161.75x
💻 LocalNext.js (Turbopack)3.901s (+12.8% 🔺)4.349s (+9.0% 🔺)0.001s (-18.1% 🟢)4.394s (+9.0% 🔺)0.493s142.07x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.575s (+5.2% 🔺)6.251s (+19.0% 🔺)0.000s (NaN%)6.807s (+20.2% 🔺)2.233s91.00x
▲ VercelExpress4.731s (+5.4% 🔺)6.054s (+6.3% 🔺)0.000s (NaN%)6.638s (+7.7% 🔺)1.907s101.03x
▲ VercelNext.js (Turbopack)7.108s (-3.4%)7.730s (-1.0%)0.000s (NaN%)8.799s (-1.6%)1.691s71.55x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress11/21
🐘 PostgresNitro21/21
▲ VercelNitro13/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express💻 Local15/21
Next.js (Turbopack)💻 Local19/21
Nitro🐘 Postgres19/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)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)
  • 🌐 Platformatic: Community world (local development)

📋 View full workflow run

@VaguelySeriousVaguelySerious 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.

workflow-web preview doesn't load runs on this PR, but did on #2752

@VaguelySerious

Copy link
Copy Markdown
Member

^ actually seems to have broken some other commit, ignore

@VaguelySeriousVaguelySerious 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.

It'd be nice if we could unify the logic here between CLI/web since it'll invariable create drift, but otherwise LGTM

@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.

Reviewed and validated the fix live. Approving.

Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.

Correctness checks:

  • The env dance holds together: ensureLocalWorldDataDirEnv() still runs before construction and before the WORKFLOW_*-derived cache key is computed, and @workflow/world-local's createWorld() reads WORKFLOW_LOCAL_DATA_DIR — so the arg-less createLocalWorld() call picks up the inspected project's data dir, matching the CLI.
  • The dynamic path is a faithful mirror of the CLI's createPostgresCliWorld() (createRequire(join(cwd, 'package.json')).resolve + import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI. @workflow/world-postgres is "type": "module", so the named createWorld export resolves without interop concerns.
  • No remaining call sites of the core stub in packages/web; @workflow/world-local properly added to dependencies with lockfile update; changeset present and accurate (patch).
  • 85/85 web tests pass locally.

CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.

Two non-blocking thoughts:

  1. For community worlds shipped as CJS, import()'s named-export detection depends on cjs-module-lexer; a mod.createWorld ?? mod.default?.createWorld fallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together.
  2. The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.

karthikscale3 added a commit that referenced this pull request Jul 7, 2026
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Addressed the review feedback:

@karthikscale3
karthikscale3 merged commit cdfac39 into mainJul 7, 2026
177 of 184 checks passed
@karthikscale3
karthikscale3 deleted the karthik/web-fix-local-world-static-injection branch July 7, 2026 22:47
karthikscale3 added a commit that referenced this pull request Jul 7, 2026
* cli: restore dynamic world loading for community backends
Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.
Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* cli: fall back to default.createWorld for CJS world packages
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update .changeset/cli-generic-world-backends.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for cdfac39 (AI decision).

This commit works around the static-injection createWorld() stub introduced on main by #2752. On stable, createWorld() in packages/core/src/runtime/world.ts is still the older dynamic-selection implementation that resolves worlds at runtime, so the bug being fixed does not exist there and applying this change would be unnecessary (and could regress the working behavior).

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

cdfac39e07e2d15c95f7ab9ff8d244b8677931bd

@github-actionsgithub-actionsBot mentioned this pull request Jul 7, 2026
VaguelySerious added a commit that referenced this pull request Jul 29, 2026
This reverts the static world-target injection and restores runtime
resolution of the world package from `WORKFLOW_TARGET_WORLD`.
Because 141 commits have landed on top of #2752, this is a surgical
revert rather than a mechanical one. Removed: the `world-target` modules
in core/builders/utils, the bundler aliases and `define`s wired through
next/nitro/nuxt/astro/sveltekit/rollup/nest, the
`@workflow/core/runtime/world-target` export, and the
pg-native/node-compat-banner helpers that only existed to support the
statically bundled world.
Kept (later work that builds on #2752):
- `createWorldFromModule` / `WorldFactoryModule` in core (used by
world-testing and the nitro dev handler)
- `world-init` / `world-init-stub` / `getWorldLazy` and their
registration of `getWorld` on globalThis, plus the #3001 isolated
route bundle regression test
- #2804 (web), #2806 (cli dynamic community backends), #3112 (world
factory alias removal), #2988 (nest vercel builder), #2925/#2908
(nitro), #2799 (sveltekit typescript stub is dropped with the
injection it existed for), next basePath support, and the windows /
canary test timeout tuning
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

web: construct worlds explicitly instead of via static-injection stub - #2804

Merged
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection
Jul 7, 2026
Merged

web: construct worlds explicitly instead of via static-injection stub#2804
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection

Conversation

@karthikscale3

Copy link
Copy Markdown
Contributor

What changed

Fixes workflow web crashing for the local and postgres backends on latest main.

Since #2752, createWorld() from @workflow/core/runtime is a static-injection stub that throws unless a framework build plugin aliases @workflow/core/runtime/world-target to the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but @workflow/web's getWorldFromEnv still called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:

Workflow target world was not statically injected. Configure a Workflow builder/framework plugin so @workflow/core/runtime/world-target is aliased to the selected world package.

The Vercel backend was unaffected because that path constructs createVercelWorld directly.

Fix

Mirror the CLI's approach in getWorldFromEnv:

  • local / @workflow/world-local → import createWorld from @workflow/world-local directly (added as a dependency of @workflow/web)
  • any other backend id (e.g. @workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call its createWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installed

Repro / validation

  • Before: workflow web against a local-world project → every RPC returns the static-injection error.
  • After: rebuilt @workflow/web and verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).
  • pnpm exec vitest run app/server/workflow-server-actions.server.test.ts — 3/3 pass
  • tsc --noEmit on @workflow/web — 15 errors, identical to the pre-existing main baseline (zero new)

🤖 Generated with Claude Code

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).
Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3
karthikscale3 requested review from a team and ijjk as code ownersJuly 7, 2026 20:25
@changeset-bot

changeset-botBot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a42603f

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

This PR includes changesets to release 16 packages
NameType
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/web-sharedPatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

@vercel

vercelBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production144202301672
✅ 💻 Local Development145302191672
✅ 📦 Local Production160502191824
✅ 🐘 Local Postgres160502191824
✅ 🪟 Windows15200152
✅ 📋 Other88701771064
Total7144010648208

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro125027
✅ example125027
✅ express125027
✅ fastify125027
✅ hono125027
✅ nextjs-turbopack14903
✅ nextjs-webpack14903
✅ nitro125027
✅ nuxt125027
✅ sveltekit14408
✅ vite125027
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack15200
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable127025
✅ e2e-local-dev-tanstack-start-127025
✅ e2e-local-postgres-nest-stable127025
✅ e2e-local-postgres-tanstack-start-127025
✅ e2e-local-prod-nest-stable127025
✅ e2e-local-prod-tanstack-start-127025
✅ e2e-vercel-prod-tanstack-start125027

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented Jul 7, 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.047s (+4.9%)1.006s (~)0.959s101.00x
💻 LocalNitro0.048s (+3.2%)1.006s (~)0.958s101.02x
💻 LocalNext.js (Turbopack)0.056s (+6.0% 🔺)1.006s (~)0.950s101.20x
🐘 PostgresNitro0.063s (-3.7%)1.012s (~)0.949s101.35x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.219s (-2.8%)1.458s (-28.8% 🟢)1.239s101.00x
▲ VercelNitro0.487s (+159.0% 🔺)2.038s (~)1.551s102.23x
▲ VercelNext.js (Turbopack)0.635s (+161.2% 🔺)2.291s (-3.7%)1.656s102.90x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express1.089s (~)2.006s (~)0.916s101.00x
💻 LocalNitro1.091s (+1.2%)2.007s (~)0.915s101.00x
💻 LocalNext.js (Turbopack)1.093s (~)2.007s (~)0.914s101.00x
🐘 PostgresNitro1.095s (~)2.010s (~)0.915s101.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.442s (+5.9% 🔺)3.166s (+4.9%)1.724s101.00x
▲ VercelExpress1.474s (+4.0%)2.878s (+1.9%)1.403s101.02x
▲ VercelNext.js (Turbopack)2.324s (-0.9%)4.149s (+15.5% 🔺)1.825s101.61x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro10.467s (~)11.016s (~)0.549s31.00x
💻 LocalNitro10.494s (~)11.024s (~)0.530s31.00x
💻 LocalExpress10.514s (~)11.022s (~)0.508s31.00x
💻 LocalNext.js (Turbopack)10.527s (~)11.025s (~)0.497s31.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro11.727s (~)14.211s (+11.9% 🔺)2.484s31.00x
▲ VercelExpress12.164s (+4.2%)13.805s (-1.0%)1.642s31.04x
▲ VercelNext.js (Turbopack)13.328s (+3.1%)14.774s (+4.2%)1.446s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express13.611s (-0.6%)14.026s (~)0.415s51.00x
🐘 PostgresNitro13.614s (-0.7%)14.019s (~)0.405s51.00x
💻 LocalNitro13.635s (~)14.029s (~)0.394s51.00x
💻 LocalNext.js (Turbopack)13.937s (+1.6%)14.030s (~)0.093s51.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro16.424s (+1.5%)18.599s (+6.7% 🔺)2.175s41.00x
▲ VercelExpress16.637s (~)18.412s (-2.8%)1.775s41.01x
▲ VercelNext.js (Turbopack)18.769s (+4.5%)20.394s (+3.2%)1.625s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.110s (-1.8%)13.018s (~)0.908s71.00x
💻 LocalExpress12.259s (~)13.025s (~)0.766s71.01x
💻 LocalNitro12.334s (+0.9%)13.026s (~)0.693s71.02x
💻 LocalNext.js (Turbopack)12.987s (+6.1% 🔺)13.459s (+3.3%)0.472s71.07x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express18.067s (+4.5%)19.946s (+4.0%)1.880s51.00x
▲ VercelNitro19.085s (+11.7% 🔺)20.914s (+11.4% 🔺)1.828s51.06x
▲ VercelNext.js (Turbopack)23.005s (+16.7% 🔺)24.524s (+13.1% 🔺)1.519s41.27x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.202s (+1.3%)2.008s (~)0.806s151.00x
💻 LocalExpress1.414s (-2.1%)2.007s (~)0.593s151.18x
💻 LocalNitro1.425s (+1.3%)2.007s (~)0.582s151.19x
💻 LocalNext.js (Turbopack)1.458s (+3.6%)2.007s (~)0.549s151.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.058s (-10.0% 🟢)4.046s (+12.3% 🔺)1.987s81.00x
▲ VercelExpress2.129s (-6.3% 🟢)3.832s (-1.8%)1.704s81.03x
▲ VercelNext.js (Turbopack)3.677s (+25.2% 🔺)5.040s (+8.6% 🔺)1.363s61.79x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.309s (-6.4% 🟢)2.222s (-10.1% 🟢)0.913s141.00x
💻 LocalNitro2.389s (+3.0%)3.009s (~)0.620s101.82x
💻 LocalNext.js (Turbopack)2.473s (-0.6%)3.010s (-3.2%)0.537s101.89x
💻 LocalExpress2.491s (-6.2% 🟢)3.009s (-3.2%)0.517s101.90x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.366s (-6.4% 🟢)4.064s (+14.2% 🔺)1.698s81.00x
▲ VercelExpress2.432s (-6.7% 🟢)4.074s (-1.1%)1.642s81.03x
▲ VercelNext.js (Turbopack)4.373s (+31.4% 🔺)5.955s (+21.3% 🔺)1.582s61.85x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.542s (-5.3% 🟢)4.136s (~)2.594s81.00x
💻 LocalNext.js (Turbopack)2.942s (-37.4% 🟢)4.442s (-19.4% 🟢)1.500s71.91x
💻 LocalNitro4.604s (+7.2% 🔺)5.515s (+13.2% 🔺)0.910s62.99x
💻 LocalExpress4.804s (+8.8% 🔺)5.345s (+3.2%)0.541s63.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.779s (-1.8%)4.829s (+7.1% 🔺)2.050s71.00x
▲ VercelExpress2.978s (+2.0%)4.815s (+9.6% 🔺)1.837s71.07x
▲ VercelNext.js (Turbopack)4.742s (+20.0% 🔺)6.242s (+8.1% 🔺)1.500s51.71x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.179s (-1.5%)2.008s (~)0.829s151.00x
💻 LocalNitro1.437s (+1.6%)2.007s (~)0.570s151.22x
💻 LocalExpress1.452s (~)2.007s (~)0.555s151.23x
💻 LocalNext.js (Turbopack)1.522s (+1.4%)2.008s (~)0.486s151.29x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.055s (+6.3% 🔺)3.862s (+5.7% 🔺)1.807s81.00x
▲ VercelNitro2.153s (+13.4% 🔺)3.930s (+17.5% 🔺)1.778s81.05x
▲ VercelNext.js (Turbopack)3.867s (+30.1% 🔺)5.350s (+13.7% 🔺)1.483s61.88x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.294s (-1.9%)2.316s (+15.4% 🔺)1.022s131.00x
💻 LocalNitro2.601s (+6.5% 🔺)3.010s (~)0.409s102.01x
💻 LocalExpress2.608s (+4.8%)3.110s (+3.4%)0.502s102.02x
💻 LocalNext.js (Turbopack)2.737s (-2.6%)3.009s (-10.0% 🟢)0.272s102.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.427s (-21.7% 🟢)4.164s (-9.0% 🟢)1.737s81.00x
▲ VercelNitro2.715s (+23.6% 🔺)4.460s (+27.2% 🔺)1.746s71.12x
▲ VercelNext.js (Turbopack)3.706s (+17.5% 🔺)5.007s (+10.3% 🔺)1.300s61.53x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.576s (-3.6%)4.011s (-6.7% 🟢)2.435s81.00x
💻 LocalExpress5.357s (+50.2% 🔺)6.214s (+24.0% 🔺)0.857s53.40x
💻 LocalNitro5.624s (+1.8%)6.015s (~)0.392s53.57x
💻 LocalNext.js (Turbopack)5.759s (+6.5% 🔺)6.418s (+6.8% 🔺)0.659s53.65x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.839s (+11.5% 🔺)4.916s (+29.2% 🔺)2.076s71.00x
▲ VercelExpress3.410s (+28.1% 🔺)5.027s (+13.3% 🔺)1.617s61.20x
▲ VercelNext.js (Turbopack)4.339s (-3.8%)6.148s (~)1.809s51.53x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.600s (~)1.041s (+1.7%)0.442s581.00x
💻 LocalNitro0.610s (+4.4%)1.005s (~)0.395s601.02x
💻 LocalExpress0.624s (+3.0%)1.022s (+1.7%)0.399s591.04x
💻 LocalNext.js (Turbopack)0.728s (+21.5% 🔺)1.023s (+1.8%)0.295s591.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.688s (+3.2%)4.312s (+7.5% 🔺)1.624s151.00x
▲ VercelExpress2.717s (+9.2% 🔺)4.414s (+11.2% 🔺)1.697s141.01x
▲ VercelNext.js (Turbopack)3.979s (-1.8%)5.460s (-3.5%)1.481s111.48x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.209s (-13.2% 🟢)2.008s (-1.1%)0.798s451.00x
💻 LocalExpress1.512s (+1.2%)2.006s (~)0.495s451.25x
💻 LocalNitro1.535s (+6.1% 🔺)2.006s (~)0.471s451.27x
💻 LocalNext.js (Turbopack)1.709s (+8.6% 🔺)2.007s (~)0.297s451.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.321s (+8.2% 🔺)8.024s (+8.7% 🔺)1.703s121.00x
▲ VercelExpress6.554s (+12.6% 🔺)8.335s (+11.4% 🔺)1.781s111.04x
▲ VercelNext.js (Turbopack)8.643s (+4.8%)10.042s (+4.7%)1.399s101.37x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.672s (-6.1% 🟢)3.192s (-0.8%)0.520s381.00x
💻 LocalExpress3.321s (~)4.009s (~)0.688s301.24x
💻 LocalNitro3.368s (+6.0% 🔺)4.043s (+2.5%)0.675s301.26x
💻 LocalNext.js (Turbopack)3.766s (+9.8% 🔺)4.144s (+3.4%)0.378s301.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.319s (+5.4% 🔺)14.027s (+1.4%)1.707s91.00x
▲ VercelNitro13.548s (+17.9% 🔺)15.518s (+20.0% 🔺)1.971s81.10x
▲ VercelNext.js (Turbopack)17.303s (+0.9%)18.740s (~)1.438s71.40x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.210s (-4.8%)1.006s (~)0.795s601.00x
💻 LocalNitro0.523s (+2.2%)1.005s (~)0.482s602.49x
💻 LocalExpress0.606s (+17.3% 🔺)1.039s (+3.4%)0.434s582.88x
💻 LocalNext.js (Turbopack)0.728s (+13.3% 🔺)1.022s (~)0.294s593.46x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.148s (+2.0%)2.715s (+3.3%)1.567s231.00x
▲ VercelNitro1.215s (+10.8% 🔺)2.857s (+19.0% 🔺)1.643s211.06x
▲ VercelNext.js (Turbopack)2.173s (+11.0% 🔺)3.410s (+1.5%)1.237s181.89x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.329s (-6.0% 🟢)1.006s (~)0.677s901.00x
💻 LocalNitro2.521s (~)3.043s (+1.1%)0.522s307.66x
💻 LocalExpress2.555s (+1.0%)3.044s (~)0.489s307.76x
💻 LocalNext.js (Turbopack)2.752s (~)3.077s (-2.2%)0.325s308.36x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.371s (-3.8%)2.931s (-3.9%)1.560s311.00x
▲ VercelNitro1.402s (+6.0% 🔺)2.882s (+15.8% 🔺)1.481s321.02x
▲ VercelNext.js (Turbopack)2.875s (+11.0% 🔺)4.427s (+9.0% 🔺)1.552s212.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.553s (-3.6%)1.160s (+7.7% 🔺)0.607s1041.00x
💻 LocalExpress5.138s (-14.1% 🟢)8.157s (-3.9%)3.019s159.29x
💻 LocalNitro5.141s (-12.2% 🟢)8.811s (+1.4%)3.671s149.30x
💻 LocalNext.js (Turbopack)6.644s (+3.3%)9.643s (+4.3%)2.999s1312.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.832s (+14.2% 🔺)3.682s (+1.2%)1.849s331.00x
▲ VercelNitro1.861s (+11.7% 🔺)3.866s (+9.2% 🔺)2.006s321.02x
▲ VercelNext.js (Turbopack)3.980s (-5.3% 🟢)5.511s (-3.8%)1.531s222.17x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.145s (-1.5%)2.000s (~)0.001s (-16.7% 🟢)2.011s (~)0.866s101.00x
💻 LocalNext.js (Turbopack)1.163s (+2.1%)1.963s (~)0.013s (+30.1% 🔺)2.022s (~)0.859s101.02x
💻 LocalExpress1.165s (~)2.004s (~)0.012s (+5.3% 🔺)2.019s (~)0.854s101.02x
💻 LocalNitro1.166s (+0.9%)2.005s (~)0.013s (+21.9% 🔺)2.021s (~)0.855s101.02x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.063s (+8.2% 🔺)3.682s (+24.3% 🔺)5.347s (+190.7% 🔺)9.559s (+83.1% 🔺)7.496s101.00x
▲ VercelExpress2.078s (+9.9% 🔺)3.546s (+9.5% 🔺)5.423s (+231.1% 🔺)9.486s (+77.4% 🔺)7.407s101.01x
▲ VercelNext.js (Turbopack)3.838s (+20.4% 🔺)4.391s (+25.5% 🔺)5.361s (+268.2% 🔺)10.975s (+70.5% 🔺)7.137s101.86x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.537s (-5.7% 🟢)2.004s (~)0.006s (+6.4% 🔺)2.027s (~)0.490s301.00x
💻 LocalNitro1.579s (~)2.009s (-1.5%)0.013s (-2.2%)2.026s (-1.6%)0.446s301.03x
💻 LocalExpress1.581s (~)2.039s (+1.4%)0.012s (+3.9%)2.059s (+1.7%)0.478s301.03x
💻 LocalNext.js (Turbopack)1.684s (+5.2% 🔺)1.967s (~)0.014s (+14.1% 🔺)2.030s (~)0.346s301.10x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro5.558s (-2.3%)7.654s (+16.1% 🔺)0.194s (-16.6% 🟢)8.385s (+13.1% 🔺)2.827s81.00x
▲ VercelExpress5.710s (+5.2% 🔺)7.460s (+5.8% 🔺)0.096s (-57.0% 🟢)8.025s (+3.2%)2.316s81.03x
▲ VercelNext.js (Turbopack)9.376s (-1.4%)10.558s (~)1.070s (+389.3% 🔺)12.346s (+6.9% 🔺)2.970s51.69x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.765s (-9.7% 🟢)1.044s (-7.0% 🟢)0.000s (+174.1% 🔺)1.060s (-7.2% 🟢)0.295s581.00x
💻 LocalExpress1.334s (-1.5%)1.949s (+1.6%)0.000s (+80.6% 🔺)1.952s (+1.6%)0.618s311.74x
💻 LocalNitro1.334s (-1.1%)1.982s (+1.7%)0.000s (+33.3% 🔺)1.985s (+1.7%)0.651s311.74x
💻 LocalNext.js (Turbopack)1.490s (+6.4% 🔺)1.975s (~)0.001s (-5.3% 🟢)2.018s (~)0.528s301.95x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.983s (-27.4% 🟢)5.018s (-4.5%)0.000s (+Infinity% 🔺)5.529s (-3.4%)2.546s111.00x
▲ VercelExpress3.326s (-36.4% 🟢)4.680s (-29.3% 🟢)0.000s (-100.0% 🟢)5.361s (-24.9% 🟢)2.035s121.11x
▲ VercelNext.js (Turbopack)4.895s (+8.8% 🔺)5.805s (+7.4% 🔺)0.000s (+Infinity% 🔺)6.619s (+7.2% 🔺)1.724s101.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

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

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.884s (+5.8% 🔺)2.606s (+7.8% 🔺)0.000s (NaN%)2.619s (+7.6% 🔺)0.735s231.00x
💻 LocalExpress3.280s (-1.2%)3.901s (~)0.001s (+500.0% 🔺)3.906s (~)0.625s161.74x
💻 LocalNitro3.288s (+1.4%)3.901s (~)0.001s (-20.0% 🟢)3.904s (~)0.616s161.75x
💻 LocalNext.js (Turbopack)3.901s (+12.8% 🔺)4.349s (+9.0% 🔺)0.001s (-18.1% 🟢)4.394s (+9.0% 🔺)0.493s142.07x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.575s (+5.2% 🔺)6.251s (+19.0% 🔺)0.000s (NaN%)6.807s (+20.2% 🔺)2.233s91.00x
▲ VercelExpress4.731s (+5.4% 🔺)6.054s (+6.3% 🔺)0.000s (NaN%)6.638s (+7.7% 🔺)1.907s101.03x
▲ VercelNext.js (Turbopack)7.108s (-3.4%)7.730s (-1.0%)0.000s (NaN%)8.799s (-1.6%)1.691s71.55x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress11/21
🐘 PostgresNitro21/21
▲ VercelNitro13/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express💻 Local15/21
Next.js (Turbopack)💻 Local19/21
Nitro🐘 Postgres19/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)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)
  • 🌐 Platformatic: Community world (local development)

📋 View full workflow run

@VaguelySeriousVaguelySerious 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.

workflow-web preview doesn't load runs on this PR, but did on #2752

@VaguelySerious

Copy link
Copy Markdown
Member

^ actually seems to have broken some other commit, ignore

@VaguelySeriousVaguelySerious 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.

It'd be nice if we could unify the logic here between CLI/web since it'll invariable create drift, but otherwise LGTM

@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.

Reviewed and validated the fix live. Approving.

Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.

Correctness checks:

  • The env dance holds together: ensureLocalWorldDataDirEnv() still runs before construction and before the WORKFLOW_*-derived cache key is computed, and @workflow/world-local's createWorld() reads WORKFLOW_LOCAL_DATA_DIR — so the arg-less createLocalWorld() call picks up the inspected project's data dir, matching the CLI.
  • The dynamic path is a faithful mirror of the CLI's createPostgresCliWorld() (createRequire(join(cwd, 'package.json')).resolve + import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI. @workflow/world-postgres is "type": "module", so the named createWorld export resolves without interop concerns.
  • No remaining call sites of the core stub in packages/web; @workflow/world-local properly added to dependencies with lockfile update; changeset present and accurate (patch).
  • 85/85 web tests pass locally.

CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.

Two non-blocking thoughts:

  1. For community worlds shipped as CJS, import()'s named-export detection depends on cjs-module-lexer; a mod.createWorld ?? mod.default?.createWorld fallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together.
  2. The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.

karthikscale3 added a commit that referenced this pull request Jul 7, 2026
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Addressed the review feedback:

@karthikscale3
karthikscale3 merged commit cdfac39 into mainJul 7, 2026
177 of 184 checks passed
@karthikscale3
karthikscale3 deleted the karthik/web-fix-local-world-static-injection branch July 7, 2026 22:47
karthikscale3 added a commit that referenced this pull request Jul 7, 2026
* cli: restore dynamic world loading for community backends
Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.
Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* cli: fall back to default.createWorld for CJS world packages
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update .changeset/cli-generic-world-backends.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for cdfac39 (AI decision).

This commit works around the static-injection createWorld() stub introduced on main by #2752. On stable, createWorld() in packages/core/src/runtime/world.ts is still the older dynamic-selection implementation that resolves worlds at runtime, so the bug being fixed does not exist there and applying this change would be unnecessary (and could regress the working behavior).

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

cdfac39e07e2d15c95f7ab9ff8d244b8677931bd

@github-actionsgithub-actionsBot mentioned this pull request Jul 7, 2026
VaguelySerious added a commit that referenced this pull request Jul 29, 2026
This reverts the static world-target injection and restores runtime
resolution of the world package from `WORKFLOW_TARGET_WORLD`.
Because 141 commits have landed on top of #2752, this is a surgical
revert rather than a mechanical one. Removed: the `world-target` modules
in core/builders/utils, the bundler aliases and `define`s wired through
next/nitro/nuxt/astro/sveltekit/rollup/nest, the
`@workflow/core/runtime/world-target` export, and the
pg-native/node-compat-banner helpers that only existed to support the
statically bundled world.
Kept (later work that builds on #2752):
- `createWorldFromModule` / `WorldFactoryModule` in core (used by
world-testing and the nitro dev handler)
- `world-init` / `world-init-stub` / `getWorldLazy` and their
registration of `getWorld` on globalThis, plus the #3001 isolated
route bundle regression test
- #2804 (web), #2806 (cli dynamic community backends), #3112 (world
factory alias removal), #2988 (nest vercel builder), #2925/#2908
(nitro), #2799 (sveltekit typescript stub is dropped with the
injection it existed for), next basePath support, and the windows /
canary test timeout tuning
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

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

web: construct worlds explicitly instead of via static-injection stub - #2804

Merged
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection
Jul 7, 2026
Merged

web: construct worlds explicitly instead of via static-injection stub#2804
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection

Conversation

@karthikscale3

Copy link
Copy Markdown
Contributor

What changed

Fixes workflow web crashing for the local and postgres backends on latest main.

Since #2752, createWorld() from @workflow/core/runtime is a static-injection stub that throws unless a framework build plugin aliases @workflow/core/runtime/world-target to the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but @workflow/web's getWorldFromEnv still called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:

Workflow target world was not statically injected. Configure a Workflow builder/framework plugin so @workflow/core/runtime/world-target is aliased to the selected world package.

The Vercel backend was unaffected because that path constructs createVercelWorld directly.

Fix

Mirror the CLI's approach in getWorldFromEnv:

  • local / @workflow/world-local → import createWorld from @workflow/world-local directly (added as a dependency of @workflow/web)
  • any other backend id (e.g. @workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call its createWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installed

Repro / validation

  • Before: workflow web against a local-world project → every RPC returns the static-injection error.
  • After: rebuilt @workflow/web and verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).
  • pnpm exec vitest run app/server/workflow-server-actions.server.test.ts — 3/3 pass
  • tsc --noEmit on @workflow/web — 15 errors, identical to the pre-existing main baseline (zero new)

🤖 Generated with Claude Code

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).
Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3
karthikscale3 requested review from a team and ijjk as code ownersJuly 7, 2026 20:25
@changeset-bot

changeset-botBot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a42603f

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

This PR includes changesets to release 16 packages
NameType
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/web-sharedPatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

@vercel

vercelBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production144202301672
✅ 💻 Local Development145302191672
✅ 📦 Local Production160502191824
✅ 🐘 Local Postgres160502191824
✅ 🪟 Windows15200152
✅ 📋 Other88701771064
Total7144010648208

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro125027
✅ example125027
✅ express125027
✅ fastify125027
✅ hono125027
✅ nextjs-turbopack14903
✅ nextjs-webpack14903
✅ nitro125027
✅ nuxt125027
✅ sveltekit14408
✅ vite125027
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack15200
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable127025
✅ e2e-local-dev-tanstack-start-127025
✅ e2e-local-postgres-nest-stable127025
✅ e2e-local-postgres-tanstack-start-127025
✅ e2e-local-prod-nest-stable127025
✅ e2e-local-prod-tanstack-start-127025
✅ e2e-vercel-prod-tanstack-start125027

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented Jul 7, 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.047s (+4.9%)1.006s (~)0.959s101.00x
💻 LocalNitro0.048s (+3.2%)1.006s (~)0.958s101.02x
💻 LocalNext.js (Turbopack)0.056s (+6.0% 🔺)1.006s (~)0.950s101.20x
🐘 PostgresNitro0.063s (-3.7%)1.012s (~)0.949s101.35x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.219s (-2.8%)1.458s (-28.8% 🟢)1.239s101.00x
▲ VercelNitro0.487s (+159.0% 🔺)2.038s (~)1.551s102.23x
▲ VercelNext.js (Turbopack)0.635s (+161.2% 🔺)2.291s (-3.7%)1.656s102.90x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express1.089s (~)2.006s (~)0.916s101.00x
💻 LocalNitro1.091s (+1.2%)2.007s (~)0.915s101.00x
💻 LocalNext.js (Turbopack)1.093s (~)2.007s (~)0.914s101.00x
🐘 PostgresNitro1.095s (~)2.010s (~)0.915s101.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.442s (+5.9% 🔺)3.166s (+4.9%)1.724s101.00x
▲ VercelExpress1.474s (+4.0%)2.878s (+1.9%)1.403s101.02x
▲ VercelNext.js (Turbopack)2.324s (-0.9%)4.149s (+15.5% 🔺)1.825s101.61x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro10.467s (~)11.016s (~)0.549s31.00x
💻 LocalNitro10.494s (~)11.024s (~)0.530s31.00x
💻 LocalExpress10.514s (~)11.022s (~)0.508s31.00x
💻 LocalNext.js (Turbopack)10.527s (~)11.025s (~)0.497s31.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro11.727s (~)14.211s (+11.9% 🔺)2.484s31.00x
▲ VercelExpress12.164s (+4.2%)13.805s (-1.0%)1.642s31.04x
▲ VercelNext.js (Turbopack)13.328s (+3.1%)14.774s (+4.2%)1.446s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express13.611s (-0.6%)14.026s (~)0.415s51.00x
🐘 PostgresNitro13.614s (-0.7%)14.019s (~)0.405s51.00x
💻 LocalNitro13.635s (~)14.029s (~)0.394s51.00x
💻 LocalNext.js (Turbopack)13.937s (+1.6%)14.030s (~)0.093s51.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro16.424s (+1.5%)18.599s (+6.7% 🔺)2.175s41.00x
▲ VercelExpress16.637s (~)18.412s (-2.8%)1.775s41.01x
▲ VercelNext.js (Turbopack)18.769s (+4.5%)20.394s (+3.2%)1.625s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.110s (-1.8%)13.018s (~)0.908s71.00x
💻 LocalExpress12.259s (~)13.025s (~)0.766s71.01x
💻 LocalNitro12.334s (+0.9%)13.026s (~)0.693s71.02x
💻 LocalNext.js (Turbopack)12.987s (+6.1% 🔺)13.459s (+3.3%)0.472s71.07x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express18.067s (+4.5%)19.946s (+4.0%)1.880s51.00x
▲ VercelNitro19.085s (+11.7% 🔺)20.914s (+11.4% 🔺)1.828s51.06x
▲ VercelNext.js (Turbopack)23.005s (+16.7% 🔺)24.524s (+13.1% 🔺)1.519s41.27x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.202s (+1.3%)2.008s (~)0.806s151.00x
💻 LocalExpress1.414s (-2.1%)2.007s (~)0.593s151.18x
💻 LocalNitro1.425s (+1.3%)2.007s (~)0.582s151.19x
💻 LocalNext.js (Turbopack)1.458s (+3.6%)2.007s (~)0.549s151.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.058s (-10.0% 🟢)4.046s (+12.3% 🔺)1.987s81.00x
▲ VercelExpress2.129s (-6.3% 🟢)3.832s (-1.8%)1.704s81.03x
▲ VercelNext.js (Turbopack)3.677s (+25.2% 🔺)5.040s (+8.6% 🔺)1.363s61.79x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.309s (-6.4% 🟢)2.222s (-10.1% 🟢)0.913s141.00x
💻 LocalNitro2.389s (+3.0%)3.009s (~)0.620s101.82x
💻 LocalNext.js (Turbopack)2.473s (-0.6%)3.010s (-3.2%)0.537s101.89x
💻 LocalExpress2.491s (-6.2% 🟢)3.009s (-3.2%)0.517s101.90x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.366s (-6.4% 🟢)4.064s (+14.2% 🔺)1.698s81.00x
▲ VercelExpress2.432s (-6.7% 🟢)4.074s (-1.1%)1.642s81.03x
▲ VercelNext.js (Turbopack)4.373s (+31.4% 🔺)5.955s (+21.3% 🔺)1.582s61.85x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.542s (-5.3% 🟢)4.136s (~)2.594s81.00x
💻 LocalNext.js (Turbopack)2.942s (-37.4% 🟢)4.442s (-19.4% 🟢)1.500s71.91x
💻 LocalNitro4.604s (+7.2% 🔺)5.515s (+13.2% 🔺)0.910s62.99x
💻 LocalExpress4.804s (+8.8% 🔺)5.345s (+3.2%)0.541s63.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.779s (-1.8%)4.829s (+7.1% 🔺)2.050s71.00x
▲ VercelExpress2.978s (+2.0%)4.815s (+9.6% 🔺)1.837s71.07x
▲ VercelNext.js (Turbopack)4.742s (+20.0% 🔺)6.242s (+8.1% 🔺)1.500s51.71x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.179s (-1.5%)2.008s (~)0.829s151.00x
💻 LocalNitro1.437s (+1.6%)2.007s (~)0.570s151.22x
💻 LocalExpress1.452s (~)2.007s (~)0.555s151.23x
💻 LocalNext.js (Turbopack)1.522s (+1.4%)2.008s (~)0.486s151.29x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.055s (+6.3% 🔺)3.862s (+5.7% 🔺)1.807s81.00x
▲ VercelNitro2.153s (+13.4% 🔺)3.930s (+17.5% 🔺)1.778s81.05x
▲ VercelNext.js (Turbopack)3.867s (+30.1% 🔺)5.350s (+13.7% 🔺)1.483s61.88x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.294s (-1.9%)2.316s (+15.4% 🔺)1.022s131.00x
💻 LocalNitro2.601s (+6.5% 🔺)3.010s (~)0.409s102.01x
💻 LocalExpress2.608s (+4.8%)3.110s (+3.4%)0.502s102.02x
💻 LocalNext.js (Turbopack)2.737s (-2.6%)3.009s (-10.0% 🟢)0.272s102.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.427s (-21.7% 🟢)4.164s (-9.0% 🟢)1.737s81.00x
▲ VercelNitro2.715s (+23.6% 🔺)4.460s (+27.2% 🔺)1.746s71.12x
▲ VercelNext.js (Turbopack)3.706s (+17.5% 🔺)5.007s (+10.3% 🔺)1.300s61.53x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.576s (-3.6%)4.011s (-6.7% 🟢)2.435s81.00x
💻 LocalExpress5.357s (+50.2% 🔺)6.214s (+24.0% 🔺)0.857s53.40x
💻 LocalNitro5.624s (+1.8%)6.015s (~)0.392s53.57x
💻 LocalNext.js (Turbopack)5.759s (+6.5% 🔺)6.418s (+6.8% 🔺)0.659s53.65x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.839s (+11.5% 🔺)4.916s (+29.2% 🔺)2.076s71.00x
▲ VercelExpress3.410s (+28.1% 🔺)5.027s (+13.3% 🔺)1.617s61.20x
▲ VercelNext.js (Turbopack)4.339s (-3.8%)6.148s (~)1.809s51.53x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.600s (~)1.041s (+1.7%)0.442s581.00x
💻 LocalNitro0.610s (+4.4%)1.005s (~)0.395s601.02x
💻 LocalExpress0.624s (+3.0%)1.022s (+1.7%)0.399s591.04x
💻 LocalNext.js (Turbopack)0.728s (+21.5% 🔺)1.023s (+1.8%)0.295s591.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.688s (+3.2%)4.312s (+7.5% 🔺)1.624s151.00x
▲ VercelExpress2.717s (+9.2% 🔺)4.414s (+11.2% 🔺)1.697s141.01x
▲ VercelNext.js (Turbopack)3.979s (-1.8%)5.460s (-3.5%)1.481s111.48x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.209s (-13.2% 🟢)2.008s (-1.1%)0.798s451.00x
💻 LocalExpress1.512s (+1.2%)2.006s (~)0.495s451.25x
💻 LocalNitro1.535s (+6.1% 🔺)2.006s (~)0.471s451.27x
💻 LocalNext.js (Turbopack)1.709s (+8.6% 🔺)2.007s (~)0.297s451.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.321s (+8.2% 🔺)8.024s (+8.7% 🔺)1.703s121.00x
▲ VercelExpress6.554s (+12.6% 🔺)8.335s (+11.4% 🔺)1.781s111.04x
▲ VercelNext.js (Turbopack)8.643s (+4.8%)10.042s (+4.7%)1.399s101.37x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.672s (-6.1% 🟢)3.192s (-0.8%)0.520s381.00x
💻 LocalExpress3.321s (~)4.009s (~)0.688s301.24x
💻 LocalNitro3.368s (+6.0% 🔺)4.043s (+2.5%)0.675s301.26x
💻 LocalNext.js (Turbopack)3.766s (+9.8% 🔺)4.144s (+3.4%)0.378s301.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.319s (+5.4% 🔺)14.027s (+1.4%)1.707s91.00x
▲ VercelNitro13.548s (+17.9% 🔺)15.518s (+20.0% 🔺)1.971s81.10x
▲ VercelNext.js (Turbopack)17.303s (+0.9%)18.740s (~)1.438s71.40x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.210s (-4.8%)1.006s (~)0.795s601.00x
💻 LocalNitro0.523s (+2.2%)1.005s (~)0.482s602.49x
💻 LocalExpress0.606s (+17.3% 🔺)1.039s (+3.4%)0.434s582.88x
💻 LocalNext.js (Turbopack)0.728s (+13.3% 🔺)1.022s (~)0.294s593.46x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.148s (+2.0%)2.715s (+3.3%)1.567s231.00x
▲ VercelNitro1.215s (+10.8% 🔺)2.857s (+19.0% 🔺)1.643s211.06x
▲ VercelNext.js (Turbopack)2.173s (+11.0% 🔺)3.410s (+1.5%)1.237s181.89x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.329s (-6.0% 🟢)1.006s (~)0.677s901.00x
💻 LocalNitro2.521s (~)3.043s (+1.1%)0.522s307.66x
💻 LocalExpress2.555s (+1.0%)3.044s (~)0.489s307.76x
💻 LocalNext.js (Turbopack)2.752s (~)3.077s (-2.2%)0.325s308.36x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.371s (-3.8%)2.931s (-3.9%)1.560s311.00x
▲ VercelNitro1.402s (+6.0% 🔺)2.882s (+15.8% 🔺)1.481s321.02x
▲ VercelNext.js (Turbopack)2.875s (+11.0% 🔺)4.427s (+9.0% 🔺)1.552s212.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.553s (-3.6%)1.160s (+7.7% 🔺)0.607s1041.00x
💻 LocalExpress5.138s (-14.1% 🟢)8.157s (-3.9%)3.019s159.29x
💻 LocalNitro5.141s (-12.2% 🟢)8.811s (+1.4%)3.671s149.30x
💻 LocalNext.js (Turbopack)6.644s (+3.3%)9.643s (+4.3%)2.999s1312.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.832s (+14.2% 🔺)3.682s (+1.2%)1.849s331.00x
▲ VercelNitro1.861s (+11.7% 🔺)3.866s (+9.2% 🔺)2.006s321.02x
▲ VercelNext.js (Turbopack)3.980s (-5.3% 🟢)5.511s (-3.8%)1.531s222.17x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.145s (-1.5%)2.000s (~)0.001s (-16.7% 🟢)2.011s (~)0.866s101.00x
💻 LocalNext.js (Turbopack)1.163s (+2.1%)1.963s (~)0.013s (+30.1% 🔺)2.022s (~)0.859s101.02x
💻 LocalExpress1.165s (~)2.004s (~)0.012s (+5.3% 🔺)2.019s (~)0.854s101.02x
💻 LocalNitro1.166s (+0.9%)2.005s (~)0.013s (+21.9% 🔺)2.021s (~)0.855s101.02x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.063s (+8.2% 🔺)3.682s (+24.3% 🔺)5.347s (+190.7% 🔺)9.559s (+83.1% 🔺)7.496s101.00x
▲ VercelExpress2.078s (+9.9% 🔺)3.546s (+9.5% 🔺)5.423s (+231.1% 🔺)9.486s (+77.4% 🔺)7.407s101.01x
▲ VercelNext.js (Turbopack)3.838s (+20.4% 🔺)4.391s (+25.5% 🔺)5.361s (+268.2% 🔺)10.975s (+70.5% 🔺)7.137s101.86x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.537s (-5.7% 🟢)2.004s (~)0.006s (+6.4% 🔺)2.027s (~)0.490s301.00x
💻 LocalNitro1.579s (~)2.009s (-1.5%)0.013s (-2.2%)2.026s (-1.6%)0.446s301.03x
💻 LocalExpress1.581s (~)2.039s (+1.4%)0.012s (+3.9%)2.059s (+1.7%)0.478s301.03x
💻 LocalNext.js (Turbopack)1.684s (+5.2% 🔺)1.967s (~)0.014s (+14.1% 🔺)2.030s (~)0.346s301.10x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro5.558s (-2.3%)7.654s (+16.1% 🔺)0.194s (-16.6% 🟢)8.385s (+13.1% 🔺)2.827s81.00x
▲ VercelExpress5.710s (+5.2% 🔺)7.460s (+5.8% 🔺)0.096s (-57.0% 🟢)8.025s (+3.2%)2.316s81.03x
▲ VercelNext.js (Turbopack)9.376s (-1.4%)10.558s (~)1.070s (+389.3% 🔺)12.346s (+6.9% 🔺)2.970s51.69x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.765s (-9.7% 🟢)1.044s (-7.0% 🟢)0.000s (+174.1% 🔺)1.060s (-7.2% 🟢)0.295s581.00x
💻 LocalExpress1.334s (-1.5%)1.949s (+1.6%)0.000s (+80.6% 🔺)1.952s (+1.6%)0.618s311.74x
💻 LocalNitro1.334s (-1.1%)1.982s (+1.7%)0.000s (+33.3% 🔺)1.985s (+1.7%)0.651s311.74x
💻 LocalNext.js (Turbopack)1.490s (+6.4% 🔺)1.975s (~)0.001s (-5.3% 🟢)2.018s (~)0.528s301.95x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.983s (-27.4% 🟢)5.018s (-4.5%)0.000s (+Infinity% 🔺)5.529s (-3.4%)2.546s111.00x
▲ VercelExpress3.326s (-36.4% 🟢)4.680s (-29.3% 🟢)0.000s (-100.0% 🟢)5.361s (-24.9% 🟢)2.035s121.11x
▲ VercelNext.js (Turbopack)4.895s (+8.8% 🔺)5.805s (+7.4% 🔺)0.000s (+Infinity% 🔺)6.619s (+7.2% 🔺)1.724s101.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

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

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.884s (+5.8% 🔺)2.606s (+7.8% 🔺)0.000s (NaN%)2.619s (+7.6% 🔺)0.735s231.00x
💻 LocalExpress3.280s (-1.2%)3.901s (~)0.001s (+500.0% 🔺)3.906s (~)0.625s161.74x
💻 LocalNitro3.288s (+1.4%)3.901s (~)0.001s (-20.0% 🟢)3.904s (~)0.616s161.75x
💻 LocalNext.js (Turbopack)3.901s (+12.8% 🔺)4.349s (+9.0% 🔺)0.001s (-18.1% 🟢)4.394s (+9.0% 🔺)0.493s142.07x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.575s (+5.2% 🔺)6.251s (+19.0% 🔺)0.000s (NaN%)6.807s (+20.2% 🔺)2.233s91.00x
▲ VercelExpress4.731s (+5.4% 🔺)6.054s (+6.3% 🔺)0.000s (NaN%)6.638s (+7.7% 🔺)1.907s101.03x
▲ VercelNext.js (Turbopack)7.108s (-3.4%)7.730s (-1.0%)0.000s (NaN%)8.799s (-1.6%)1.691s71.55x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress11/21
🐘 PostgresNitro21/21
▲ VercelNitro13/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express💻 Local15/21
Next.js (Turbopack)💻 Local19/21
Nitro🐘 Postgres19/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)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)
  • 🌐 Platformatic: Community world (local development)

📋 View full workflow run

@VaguelySeriousVaguelySerious 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.

workflow-web preview doesn't load runs on this PR, but did on #2752

@VaguelySerious

Copy link
Copy Markdown
Member

^ actually seems to have broken some other commit, ignore

@VaguelySeriousVaguelySerious 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.

It'd be nice if we could unify the logic here between CLI/web since it'll invariable create drift, but otherwise LGTM

@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.

Reviewed and validated the fix live. Approving.

Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.

Correctness checks:

  • The env dance holds together: ensureLocalWorldDataDirEnv() still runs before construction and before the WORKFLOW_*-derived cache key is computed, and @workflow/world-local's createWorld() reads WORKFLOW_LOCAL_DATA_DIR — so the arg-less createLocalWorld() call picks up the inspected project's data dir, matching the CLI.
  • The dynamic path is a faithful mirror of the CLI's createPostgresCliWorld() (createRequire(join(cwd, 'package.json')).resolve + import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI. @workflow/world-postgres is "type": "module", so the named createWorld export resolves without interop concerns.
  • No remaining call sites of the core stub in packages/web; @workflow/world-local properly added to dependencies with lockfile update; changeset present and accurate (patch).
  • 85/85 web tests pass locally.

CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.

Two non-blocking thoughts:

  1. For community worlds shipped as CJS, import()'s named-export detection depends on cjs-module-lexer; a mod.createWorld ?? mod.default?.createWorld fallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together.
  2. The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.

karthikscale3 added a commit that referenced this pull request Jul 7, 2026
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Addressed the review feedback:

@karthikscale3
karthikscale3 merged commit cdfac39 into mainJul 7, 2026
177 of 184 checks passed
@karthikscale3
karthikscale3 deleted the karthik/web-fix-local-world-static-injection branch July 7, 2026 22:47
karthikscale3 added a commit that referenced this pull request Jul 7, 2026
* cli: restore dynamic world loading for community backends
Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.
Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* cli: fall back to default.createWorld for CJS world packages
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update .changeset/cli-generic-world-backends.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for cdfac39 (AI decision).

This commit works around the static-injection createWorld() stub introduced on main by #2752. On stable, createWorld() in packages/core/src/runtime/world.ts is still the older dynamic-selection implementation that resolves worlds at runtime, so the bug being fixed does not exist there and applying this change would be unnecessary (and could regress the working behavior).

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

cdfac39e07e2d15c95f7ab9ff8d244b8677931bd

@github-actionsgithub-actionsBot mentioned this pull request Jul 7, 2026
VaguelySerious added a commit that referenced this pull request Jul 29, 2026
This reverts the static world-target injection and restores runtime
resolution of the world package from `WORKFLOW_TARGET_WORLD`.
Because 141 commits have landed on top of #2752, this is a surgical
revert rather than a mechanical one. Removed: the `world-target` modules
in core/builders/utils, the bundler aliases and `define`s wired through
next/nitro/nuxt/astro/sveltekit/rollup/nest, the
`@workflow/core/runtime/world-target` export, and the
pg-native/node-compat-banner helpers that only existed to support the
statically bundled world.
Kept (later work that builds on #2752):
- `createWorldFromModule` / `WorldFactoryModule` in core (used by
world-testing and the nitro dev handler)
- `world-init` / `world-init-stub` / `getWorldLazy` and their
registration of `getWorld` on globalThis, plus the #3001 isolated
route bundle regression test
- #2804 (web), #2806 (cli dynamic community backends), #3112 (world
factory alias removal), #2988 (nest vercel builder), #2925/#2908
(nitro), #2799 (sveltekit typescript stub is dropped with the
injection it existed for), next basePath support, and the windows /
canary test timeout tuning
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@karthikscale3@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' web: construct worlds explicitly instead of via static-injection stub by karthikscale3 · Pull Request #2804 · vercel/workflow · GitHub
Skip to content

web: construct worlds explicitly instead of via static-injection stub - #2804

Merged
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection
Jul 7, 2026
Merged

web: construct worlds explicitly instead of via static-injection stub#2804
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection

Conversation

@karthikscale3

Copy link
Copy Markdown
Contributor

What changed

Fixes workflow web crashing for the local and postgres backends on latest main.

Since #2752, createWorld() from @workflow/core/runtime is a static-injection stub that throws unless a framework build plugin aliases @workflow/core/runtime/world-target to the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but @workflow/web's getWorldFromEnv still called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:

Workflow target world was not statically injected. Configure a Workflow builder/framework plugin so @workflow/core/runtime/world-target is aliased to the selected world package.

The Vercel backend was unaffected because that path constructs createVercelWorld directly.

Fix

Mirror the CLI's approach in getWorldFromEnv:

  • local / @workflow/world-local → import createWorld from @workflow/world-local directly (added as a dependency of @workflow/web)
  • any other backend id (e.g. @workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call its createWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installed

Repro / validation

  • Before: workflow web against a local-world project → every RPC returns the static-injection error.
  • After: rebuilt @workflow/web and verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).
  • pnpm exec vitest run app/server/workflow-server-actions.server.test.ts — 3/3 pass
  • tsc --noEmit on @workflow/web — 15 errors, identical to the pre-existing main baseline (zero new)

🤖 Generated with Claude Code

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).
Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3
karthikscale3 requested review from a team and ijjk as code ownersJuly 7, 2026 20:25
@changeset-bot

changeset-botBot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a42603f

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

This PR includes changesets to release 16 packages
NameType
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/web-sharedPatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

@vercel

vercelBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production144202301672
✅ 💻 Local Development145302191672
✅ 📦 Local Production160502191824
✅ 🐘 Local Postgres160502191824
✅ 🪟 Windows15200152
✅ 📋 Other88701771064
Total7144010648208

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro125027
✅ example125027
✅ express125027
✅ fastify125027
✅ hono125027
✅ nextjs-turbopack14903
✅ nextjs-webpack14903
✅ nitro125027
✅ nuxt125027
✅ sveltekit14408
✅ vite125027
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack15200
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable127025
✅ e2e-local-dev-tanstack-start-127025
✅ e2e-local-postgres-nest-stable127025
✅ e2e-local-postgres-tanstack-start-127025
✅ e2e-local-prod-nest-stable127025
✅ e2e-local-prod-tanstack-start-127025
✅ e2e-vercel-prod-tanstack-start125027

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented Jul 7, 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.047s (+4.9%)1.006s (~)0.959s101.00x
💻 LocalNitro0.048s (+3.2%)1.006s (~)0.958s101.02x
💻 LocalNext.js (Turbopack)0.056s (+6.0% 🔺)1.006s (~)0.950s101.20x
🐘 PostgresNitro0.063s (-3.7%)1.012s (~)0.949s101.35x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.219s (-2.8%)1.458s (-28.8% 🟢)1.239s101.00x
▲ VercelNitro0.487s (+159.0% 🔺)2.038s (~)1.551s102.23x
▲ VercelNext.js (Turbopack)0.635s (+161.2% 🔺)2.291s (-3.7%)1.656s102.90x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express1.089s (~)2.006s (~)0.916s101.00x
💻 LocalNitro1.091s (+1.2%)2.007s (~)0.915s101.00x
💻 LocalNext.js (Turbopack)1.093s (~)2.007s (~)0.914s101.00x
🐘 PostgresNitro1.095s (~)2.010s (~)0.915s101.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.442s (+5.9% 🔺)3.166s (+4.9%)1.724s101.00x
▲ VercelExpress1.474s (+4.0%)2.878s (+1.9%)1.403s101.02x
▲ VercelNext.js (Turbopack)2.324s (-0.9%)4.149s (+15.5% 🔺)1.825s101.61x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro10.467s (~)11.016s (~)0.549s31.00x
💻 LocalNitro10.494s (~)11.024s (~)0.530s31.00x
💻 LocalExpress10.514s (~)11.022s (~)0.508s31.00x
💻 LocalNext.js (Turbopack)10.527s (~)11.025s (~)0.497s31.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro11.727s (~)14.211s (+11.9% 🔺)2.484s31.00x
▲ VercelExpress12.164s (+4.2%)13.805s (-1.0%)1.642s31.04x
▲ VercelNext.js (Turbopack)13.328s (+3.1%)14.774s (+4.2%)1.446s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express13.611s (-0.6%)14.026s (~)0.415s51.00x
🐘 PostgresNitro13.614s (-0.7%)14.019s (~)0.405s51.00x
💻 LocalNitro13.635s (~)14.029s (~)0.394s51.00x
💻 LocalNext.js (Turbopack)13.937s (+1.6%)14.030s (~)0.093s51.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro16.424s (+1.5%)18.599s (+6.7% 🔺)2.175s41.00x
▲ VercelExpress16.637s (~)18.412s (-2.8%)1.775s41.01x
▲ VercelNext.js (Turbopack)18.769s (+4.5%)20.394s (+3.2%)1.625s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.110s (-1.8%)13.018s (~)0.908s71.00x
💻 LocalExpress12.259s (~)13.025s (~)0.766s71.01x
💻 LocalNitro12.334s (+0.9%)13.026s (~)0.693s71.02x
💻 LocalNext.js (Turbopack)12.987s (+6.1% 🔺)13.459s (+3.3%)0.472s71.07x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express18.067s (+4.5%)19.946s (+4.0%)1.880s51.00x
▲ VercelNitro19.085s (+11.7% 🔺)20.914s (+11.4% 🔺)1.828s51.06x
▲ VercelNext.js (Turbopack)23.005s (+16.7% 🔺)24.524s (+13.1% 🔺)1.519s41.27x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.202s (+1.3%)2.008s (~)0.806s151.00x
💻 LocalExpress1.414s (-2.1%)2.007s (~)0.593s151.18x
💻 LocalNitro1.425s (+1.3%)2.007s (~)0.582s151.19x
💻 LocalNext.js (Turbopack)1.458s (+3.6%)2.007s (~)0.549s151.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.058s (-10.0% 🟢)4.046s (+12.3% 🔺)1.987s81.00x
▲ VercelExpress2.129s (-6.3% 🟢)3.832s (-1.8%)1.704s81.03x
▲ VercelNext.js (Turbopack)3.677s (+25.2% 🔺)5.040s (+8.6% 🔺)1.363s61.79x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.309s (-6.4% 🟢)2.222s (-10.1% 🟢)0.913s141.00x
💻 LocalNitro2.389s (+3.0%)3.009s (~)0.620s101.82x
💻 LocalNext.js (Turbopack)2.473s (-0.6%)3.010s (-3.2%)0.537s101.89x
💻 LocalExpress2.491s (-6.2% 🟢)3.009s (-3.2%)0.517s101.90x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.366s (-6.4% 🟢)4.064s (+14.2% 🔺)1.698s81.00x
▲ VercelExpress2.432s (-6.7% 🟢)4.074s (-1.1%)1.642s81.03x
▲ VercelNext.js (Turbopack)4.373s (+31.4% 🔺)5.955s (+21.3% 🔺)1.582s61.85x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.542s (-5.3% 🟢)4.136s (~)2.594s81.00x
💻 LocalNext.js (Turbopack)2.942s (-37.4% 🟢)4.442s (-19.4% 🟢)1.500s71.91x
💻 LocalNitro4.604s (+7.2% 🔺)5.515s (+13.2% 🔺)0.910s62.99x
💻 LocalExpress4.804s (+8.8% 🔺)5.345s (+3.2%)0.541s63.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.779s (-1.8%)4.829s (+7.1% 🔺)2.050s71.00x
▲ VercelExpress2.978s (+2.0%)4.815s (+9.6% 🔺)1.837s71.07x
▲ VercelNext.js (Turbopack)4.742s (+20.0% 🔺)6.242s (+8.1% 🔺)1.500s51.71x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.179s (-1.5%)2.008s (~)0.829s151.00x
💻 LocalNitro1.437s (+1.6%)2.007s (~)0.570s151.22x
💻 LocalExpress1.452s (~)2.007s (~)0.555s151.23x
💻 LocalNext.js (Turbopack)1.522s (+1.4%)2.008s (~)0.486s151.29x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.055s (+6.3% 🔺)3.862s (+5.7% 🔺)1.807s81.00x
▲ VercelNitro2.153s (+13.4% 🔺)3.930s (+17.5% 🔺)1.778s81.05x
▲ VercelNext.js (Turbopack)3.867s (+30.1% 🔺)5.350s (+13.7% 🔺)1.483s61.88x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.294s (-1.9%)2.316s (+15.4% 🔺)1.022s131.00x
💻 LocalNitro2.601s (+6.5% 🔺)3.010s (~)0.409s102.01x
💻 LocalExpress2.608s (+4.8%)3.110s (+3.4%)0.502s102.02x
💻 LocalNext.js (Turbopack)2.737s (-2.6%)3.009s (-10.0% 🟢)0.272s102.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.427s (-21.7% 🟢)4.164s (-9.0% 🟢)1.737s81.00x
▲ VercelNitro2.715s (+23.6% 🔺)4.460s (+27.2% 🔺)1.746s71.12x
▲ VercelNext.js (Turbopack)3.706s (+17.5% 🔺)5.007s (+10.3% 🔺)1.300s61.53x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.576s (-3.6%)4.011s (-6.7% 🟢)2.435s81.00x
💻 LocalExpress5.357s (+50.2% 🔺)6.214s (+24.0% 🔺)0.857s53.40x
💻 LocalNitro5.624s (+1.8%)6.015s (~)0.392s53.57x
💻 LocalNext.js (Turbopack)5.759s (+6.5% 🔺)6.418s (+6.8% 🔺)0.659s53.65x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.839s (+11.5% 🔺)4.916s (+29.2% 🔺)2.076s71.00x
▲ VercelExpress3.410s (+28.1% 🔺)5.027s (+13.3% 🔺)1.617s61.20x
▲ VercelNext.js (Turbopack)4.339s (-3.8%)6.148s (~)1.809s51.53x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.600s (~)1.041s (+1.7%)0.442s581.00x
💻 LocalNitro0.610s (+4.4%)1.005s (~)0.395s601.02x
💻 LocalExpress0.624s (+3.0%)1.022s (+1.7%)0.399s591.04x
💻 LocalNext.js (Turbopack)0.728s (+21.5% 🔺)1.023s (+1.8%)0.295s591.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.688s (+3.2%)4.312s (+7.5% 🔺)1.624s151.00x
▲ VercelExpress2.717s (+9.2% 🔺)4.414s (+11.2% 🔺)1.697s141.01x
▲ VercelNext.js (Turbopack)3.979s (-1.8%)5.460s (-3.5%)1.481s111.48x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.209s (-13.2% 🟢)2.008s (-1.1%)0.798s451.00x
💻 LocalExpress1.512s (+1.2%)2.006s (~)0.495s451.25x
💻 LocalNitro1.535s (+6.1% 🔺)2.006s (~)0.471s451.27x
💻 LocalNext.js (Turbopack)1.709s (+8.6% 🔺)2.007s (~)0.297s451.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.321s (+8.2% 🔺)8.024s (+8.7% 🔺)1.703s121.00x
▲ VercelExpress6.554s (+12.6% 🔺)8.335s (+11.4% 🔺)1.781s111.04x
▲ VercelNext.js (Turbopack)8.643s (+4.8%)10.042s (+4.7%)1.399s101.37x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.672s (-6.1% 🟢)3.192s (-0.8%)0.520s381.00x
💻 LocalExpress3.321s (~)4.009s (~)0.688s301.24x
💻 LocalNitro3.368s (+6.0% 🔺)4.043s (+2.5%)0.675s301.26x
💻 LocalNext.js (Turbopack)3.766s (+9.8% 🔺)4.144s (+3.4%)0.378s301.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.319s (+5.4% 🔺)14.027s (+1.4%)1.707s91.00x
▲ VercelNitro13.548s (+17.9% 🔺)15.518s (+20.0% 🔺)1.971s81.10x
▲ VercelNext.js (Turbopack)17.303s (+0.9%)18.740s (~)1.438s71.40x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.210s (-4.8%)1.006s (~)0.795s601.00x
💻 LocalNitro0.523s (+2.2%)1.005s (~)0.482s602.49x
💻 LocalExpress0.606s (+17.3% 🔺)1.039s (+3.4%)0.434s582.88x
💻 LocalNext.js (Turbopack)0.728s (+13.3% 🔺)1.022s (~)0.294s593.46x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.148s (+2.0%)2.715s (+3.3%)1.567s231.00x
▲ VercelNitro1.215s (+10.8% 🔺)2.857s (+19.0% 🔺)1.643s211.06x
▲ VercelNext.js (Turbopack)2.173s (+11.0% 🔺)3.410s (+1.5%)1.237s181.89x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.329s (-6.0% 🟢)1.006s (~)0.677s901.00x
💻 LocalNitro2.521s (~)3.043s (+1.1%)0.522s307.66x
💻 LocalExpress2.555s (+1.0%)3.044s (~)0.489s307.76x
💻 LocalNext.js (Turbopack)2.752s (~)3.077s (-2.2%)0.325s308.36x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.371s (-3.8%)2.931s (-3.9%)1.560s311.00x
▲ VercelNitro1.402s (+6.0% 🔺)2.882s (+15.8% 🔺)1.481s321.02x
▲ VercelNext.js (Turbopack)2.875s (+11.0% 🔺)4.427s (+9.0% 🔺)1.552s212.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.553s (-3.6%)1.160s (+7.7% 🔺)0.607s1041.00x
💻 LocalExpress5.138s (-14.1% 🟢)8.157s (-3.9%)3.019s159.29x
💻 LocalNitro5.141s (-12.2% 🟢)8.811s (+1.4%)3.671s149.30x
💻 LocalNext.js (Turbopack)6.644s (+3.3%)9.643s (+4.3%)2.999s1312.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.832s (+14.2% 🔺)3.682s (+1.2%)1.849s331.00x
▲ VercelNitro1.861s (+11.7% 🔺)3.866s (+9.2% 🔺)2.006s321.02x
▲ VercelNext.js (Turbopack)3.980s (-5.3% 🟢)5.511s (-3.8%)1.531s222.17x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.145s (-1.5%)2.000s (~)0.001s (-16.7% 🟢)2.011s (~)0.866s101.00x
💻 LocalNext.js (Turbopack)1.163s (+2.1%)1.963s (~)0.013s (+30.1% 🔺)2.022s (~)0.859s101.02x
💻 LocalExpress1.165s (~)2.004s (~)0.012s (+5.3% 🔺)2.019s (~)0.854s101.02x
💻 LocalNitro1.166s (+0.9%)2.005s (~)0.013s (+21.9% 🔺)2.021s (~)0.855s101.02x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.063s (+8.2% 🔺)3.682s (+24.3% 🔺)5.347s (+190.7% 🔺)9.559s (+83.1% 🔺)7.496s101.00x
▲ VercelExpress2.078s (+9.9% 🔺)3.546s (+9.5% 🔺)5.423s (+231.1% 🔺)9.486s (+77.4% 🔺)7.407s101.01x
▲ VercelNext.js (Turbopack)3.838s (+20.4% 🔺)4.391s (+25.5% 🔺)5.361s (+268.2% 🔺)10.975s (+70.5% 🔺)7.137s101.86x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.537s (-5.7% 🟢)2.004s (~)0.006s (+6.4% 🔺)2.027s (~)0.490s301.00x
💻 LocalNitro1.579s (~)2.009s (-1.5%)0.013s (-2.2%)2.026s (-1.6%)0.446s301.03x
💻 LocalExpress1.581s (~)2.039s (+1.4%)0.012s (+3.9%)2.059s (+1.7%)0.478s301.03x
💻 LocalNext.js (Turbopack)1.684s (+5.2% 🔺)1.967s (~)0.014s (+14.1% 🔺)2.030s (~)0.346s301.10x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro5.558s (-2.3%)7.654s (+16.1% 🔺)0.194s (-16.6% 🟢)8.385s (+13.1% 🔺)2.827s81.00x
▲ VercelExpress5.710s (+5.2% 🔺)7.460s (+5.8% 🔺)0.096s (-57.0% 🟢)8.025s (+3.2%)2.316s81.03x
▲ VercelNext.js (Turbopack)9.376s (-1.4%)10.558s (~)1.070s (+389.3% 🔺)12.346s (+6.9% 🔺)2.970s51.69x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.765s (-9.7% 🟢)1.044s (-7.0% 🟢)0.000s (+174.1% 🔺)1.060s (-7.2% 🟢)0.295s581.00x
💻 LocalExpress1.334s (-1.5%)1.949s (+1.6%)0.000s (+80.6% 🔺)1.952s (+1.6%)0.618s311.74x
💻 LocalNitro1.334s (-1.1%)1.982s (+1.7%)0.000s (+33.3% 🔺)1.985s (+1.7%)0.651s311.74x
💻 LocalNext.js (Turbopack)1.490s (+6.4% 🔺)1.975s (~)0.001s (-5.3% 🟢)2.018s (~)0.528s301.95x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.983s (-27.4% 🟢)5.018s (-4.5%)0.000s (+Infinity% 🔺)5.529s (-3.4%)2.546s111.00x
▲ VercelExpress3.326s (-36.4% 🟢)4.680s (-29.3% 🟢)0.000s (-100.0% 🟢)5.361s (-24.9% 🟢)2.035s121.11x
▲ VercelNext.js (Turbopack)4.895s (+8.8% 🔺)5.805s (+7.4% 🔺)0.000s (+Infinity% 🔺)6.619s (+7.2% 🔺)1.724s101.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

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

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.884s (+5.8% 🔺)2.606s (+7.8% 🔺)0.000s (NaN%)2.619s (+7.6% 🔺)0.735s231.00x
💻 LocalExpress3.280s (-1.2%)3.901s (~)0.001s (+500.0% 🔺)3.906s (~)0.625s161.74x
💻 LocalNitro3.288s (+1.4%)3.901s (~)0.001s (-20.0% 🟢)3.904s (~)0.616s161.75x
💻 LocalNext.js (Turbopack)3.901s (+12.8% 🔺)4.349s (+9.0% 🔺)0.001s (-18.1% 🟢)4.394s (+9.0% 🔺)0.493s142.07x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.575s (+5.2% 🔺)6.251s (+19.0% 🔺)0.000s (NaN%)6.807s (+20.2% 🔺)2.233s91.00x
▲ VercelExpress4.731s (+5.4% 🔺)6.054s (+6.3% 🔺)0.000s (NaN%)6.638s (+7.7% 🔺)1.907s101.03x
▲ VercelNext.js (Turbopack)7.108s (-3.4%)7.730s (-1.0%)0.000s (NaN%)8.799s (-1.6%)1.691s71.55x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress11/21
🐘 PostgresNitro21/21
▲ VercelNitro13/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express💻 Local15/21
Next.js (Turbopack)💻 Local19/21
Nitro🐘 Postgres19/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)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)
  • 🌐 Platformatic: Community world (local development)

📋 View full workflow run

@VaguelySeriousVaguelySerious 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.

workflow-web preview doesn't load runs on this PR, but did on #2752

@VaguelySerious

Copy link
Copy Markdown
Member

^ actually seems to have broken some other commit, ignore

@VaguelySeriousVaguelySerious 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.

It'd be nice if we could unify the logic here between CLI/web since it'll invariable create drift, but otherwise LGTM

@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.

Reviewed and validated the fix live. Approving.

Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.

Correctness checks:

  • The env dance holds together: ensureLocalWorldDataDirEnv() still runs before construction and before the WORKFLOW_*-derived cache key is computed, and @workflow/world-local's createWorld() reads WORKFLOW_LOCAL_DATA_DIR — so the arg-less createLocalWorld() call picks up the inspected project's data dir, matching the CLI.
  • The dynamic path is a faithful mirror of the CLI's createPostgresCliWorld() (createRequire(join(cwd, 'package.json')).resolve + import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI. @workflow/world-postgres is "type": "module", so the named createWorld export resolves without interop concerns.
  • No remaining call sites of the core stub in packages/web; @workflow/world-local properly added to dependencies with lockfile update; changeset present and accurate (patch).
  • 85/85 web tests pass locally.

CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.

Two non-blocking thoughts:

  1. For community worlds shipped as CJS, import()'s named-export detection depends on cjs-module-lexer; a mod.createWorld ?? mod.default?.createWorld fallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together.
  2. The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.

karthikscale3 added a commit that referenced this pull request Jul 7, 2026
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Addressed the review feedback:

@karthikscale3
karthikscale3 merged commit cdfac39 into mainJul 7, 2026
177 of 184 checks passed
@karthikscale3
karthikscale3 deleted the karthik/web-fix-local-world-static-injection branch July 7, 2026 22:47
karthikscale3 added a commit that referenced this pull request Jul 7, 2026
* cli: restore dynamic world loading for community backends
Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.
Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* cli: fall back to default.createWorld for CJS world packages
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update .changeset/cli-generic-world-backends.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for cdfac39 (AI decision).

This commit works around the static-injection createWorld() stub introduced on main by #2752. On stable, createWorld() in packages/core/src/runtime/world.ts is still the older dynamic-selection implementation that resolves worlds at runtime, so the bug being fixed does not exist there and applying this change would be unnecessary (and could regress the working behavior).

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

cdfac39e07e2d15c95f7ab9ff8d244b8677931bd

@github-actionsgithub-actionsBot mentioned this pull request Jul 7, 2026
VaguelySerious added a commit that referenced this pull request Jul 29, 2026
This reverts the static world-target injection and restores runtime
resolution of the world package from `WORKFLOW_TARGET_WORLD`.
Because 141 commits have landed on top of #2752, this is a surgical
revert rather than a mechanical one. Removed: the `world-target` modules
in core/builders/utils, the bundler aliases and `define`s wired through
next/nitro/nuxt/astro/sveltekit/rollup/nest, the
`@workflow/core/runtime/world-target` export, and the
pg-native/node-compat-banner helpers that only existed to support the
statically bundled world.
Kept (later work that builds on #2752):
- `createWorldFromModule` / `WorldFactoryModule` in core (used by
world-testing and the nitro dev handler)
- `world-init` / `world-init-stub` / `getWorldLazy` and their
registration of `getWorld` on globalThis, plus the #3001 isolated
route bundle regression test
- #2804 (web), #2806 (cli dynamic community backends), #3112 (world
factory alias removal), #2988 (nest vercel builder), #2925/#2908
(nitro), #2799 (sveltekit typescript stub is dropped with the
injection it existed for), next basePath support, and the windows /
canary test timeout tuning
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@karthikscale3@VaguelySerious@TooTallNate
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); web: construct worlds explicitly instead of via static-injection stub by karthikscale3 · Pull Request #2804 · vercel/workflow · GitHub
Skip to content

web: construct worlds explicitly instead of via static-injection stub - #2804

Merged
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection
Jul 7, 2026
Merged

web: construct worlds explicitly instead of via static-injection stub#2804
karthikscale3 merged 2 commits into
mainfrom
karthik/web-fix-local-world-static-injection

Conversation

@karthikscale3

Copy link
Copy Markdown
Contributor

What changed

Fixes workflow web crashing for the local and postgres backends on latest main.

Since #2752, createWorld() from @workflow/core/runtime is a static-injection stub that throws unless a framework build plugin aliases @workflow/core/runtime/world-target to the selected world package at the host app's build time. The CLI was migrated to construct worlds explicitly (packages/cli/src/lib/inspect/setup.ts), but @workflow/web's getWorldFromEnv still called the stub. Since the web UI selects its backend at runtime via env, no build plugin ever aliases its bundle, so every server action failed with:

Workflow target world was not statically injected. Configure a Workflow builder/framework plugin so @workflow/core/runtime/world-target is aliased to the selected world package.

The Vercel backend was unaffected because that path constructs createVercelWorld directly.

Fix

Mirror the CLI's approach in getWorldFromEnv:

  • local / @workflow/world-local → import createWorld from @workflow/world-local directly (added as a dependency of @workflow/web)
  • any other backend id (e.g. @workflow/world-postgres, community worlds) → resolve the package from the inspected project's directory (WORKFLOW_OBSERVABILITY_CWD) and call its createWorld(), preserving the pre-Statically inject workflow world target #2752 dynamic-selection behavior with a clear error when the package isn't installed

Repro / validation

  • Before: workflow web against a local-world project → every RPC returns the static-injection error.
  • After: rebuilt @workflow/web and verified end-to-end against a local-world project (runs/steps/events/hooks list + detail + lazy hook-token fetch all working), and against the Vercel backend (unaffected path, still works).
  • pnpm exec vitest run app/server/workflow-server-actions.server.test.ts — 3/3 pass
  • tsc --noEmit on @workflow/web — 15 errors, identical to the pre-existing main baseline (zero new)

🤖 Generated with Claude Code

Since #2752, createWorld() from @workflow/core/runtime is a stub that
throws unless a framework build plugin aliases it to a world package.
The CLI was migrated to construct worlds directly, but @workflow/web
still called the stub, so 'workflow web' crashed with 'Workflow target
world was not statically injected' for local and postgres backends
(the vercel path was unaffected since it constructs the world directly).
Mirror the CLI: import the local world statically and resolve any other
configured world package from the inspected project's directory.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3
karthikscale3 requested review from a team and ijjk as code ownersJuly 7, 2026 20:25
@changeset-bot

changeset-botBot commented Jul 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a42603f

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

This PR includes changesets to release 16 packages
NameType
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/web-sharedPatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

@vercel

vercelBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

PassedFailedSkippedTotal
✅ ▲ Vercel Production144202301672
✅ 💻 Local Development145302191672
✅ 📦 Local Production160502191824
✅ 🐘 Local Postgres160502191824
✅ 🪟 Windows15200152
✅ 📋 Other88701771064
Total7144010648208

Details by Category

✅ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro125027
✅ example125027
✅ express125027
✅ fastify125027
✅ hono125027
✅ nextjs-turbopack14903
✅ nextjs-webpack14903
✅ nitro125027
✅ nuxt125027
✅ sveltekit14408
✅ vite125027
✅ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable127025
✅ express-stable127025
✅ fastify-stable127025
✅ hono-stable127025
✅ nextjs-turbopack-canary133019
✅ nextjs-turbopack-stable15200
✅ nextjs-webpack-canary133019
✅ nextjs-webpack-stable15200
✅ nitro-stable127025
✅ nuxt-stable127025
✅ sveltekit-stable14606
✅ vite-stable127025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack15200
✅ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable127025
✅ e2e-local-dev-tanstack-start-127025
✅ e2e-local-postgres-nest-stable127025
✅ e2e-local-postgres-tanstack-start-127025
✅ e2e-local-prod-nest-stable127025
✅ e2e-local-prod-tanstack-start-127025
✅ e2e-vercel-prod-tanstack-start125027

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented Jul 7, 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.047s (+4.9%)1.006s (~)0.959s101.00x
💻 LocalNitro0.048s (+3.2%)1.006s (~)0.958s101.02x
💻 LocalNext.js (Turbopack)0.056s (+6.0% 🔺)1.006s (~)0.950s101.20x
🐘 PostgresNitro0.063s (-3.7%)1.012s (~)0.949s101.35x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.219s (-2.8%)1.458s (-28.8% 🟢)1.239s101.00x
▲ VercelNitro0.487s (+159.0% 🔺)2.038s (~)1.551s102.23x
▲ VercelNext.js (Turbopack)0.635s (+161.2% 🔺)2.291s (-3.7%)1.656s102.90x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express1.089s (~)2.006s (~)0.916s101.00x
💻 LocalNitro1.091s (+1.2%)2.007s (~)0.915s101.00x
💻 LocalNext.js (Turbopack)1.093s (~)2.007s (~)0.914s101.00x
🐘 PostgresNitro1.095s (~)2.010s (~)0.915s101.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.442s (+5.9% 🔺)3.166s (+4.9%)1.724s101.00x
▲ VercelExpress1.474s (+4.0%)2.878s (+1.9%)1.403s101.02x
▲ VercelNext.js (Turbopack)2.324s (-0.9%)4.149s (+15.5% 🔺)1.825s101.61x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro10.467s (~)11.016s (~)0.549s31.00x
💻 LocalNitro10.494s (~)11.024s (~)0.530s31.00x
💻 LocalExpress10.514s (~)11.022s (~)0.508s31.00x
💻 LocalNext.js (Turbopack)10.527s (~)11.025s (~)0.497s31.01x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro11.727s (~)14.211s (+11.9% 🔺)2.484s31.00x
▲ VercelExpress12.164s (+4.2%)13.805s (-1.0%)1.642s31.04x
▲ VercelNext.js (Turbopack)13.328s (+3.1%)14.774s (+4.2%)1.446s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express13.611s (-0.6%)14.026s (~)0.415s51.00x
🐘 PostgresNitro13.614s (-0.7%)14.019s (~)0.405s51.00x
💻 LocalNitro13.635s (~)14.029s (~)0.394s51.00x
💻 LocalNext.js (Turbopack)13.937s (+1.6%)14.030s (~)0.093s51.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro16.424s (+1.5%)18.599s (+6.7% 🔺)2.175s41.00x
▲ VercelExpress16.637s (~)18.412s (-2.8%)1.775s41.01x
▲ VercelNext.js (Turbopack)18.769s (+4.5%)20.394s (+3.2%)1.625s31.14x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.110s (-1.8%)13.018s (~)0.908s71.00x
💻 LocalExpress12.259s (~)13.025s (~)0.766s71.01x
💻 LocalNitro12.334s (+0.9%)13.026s (~)0.693s71.02x
💻 LocalNext.js (Turbopack)12.987s (+6.1% 🔺)13.459s (+3.3%)0.472s71.07x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express18.067s (+4.5%)19.946s (+4.0%)1.880s51.00x
▲ VercelNitro19.085s (+11.7% 🔺)20.914s (+11.4% 🔺)1.828s51.06x
▲ VercelNext.js (Turbopack)23.005s (+16.7% 🔺)24.524s (+13.1% 🔺)1.519s41.27x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.202s (+1.3%)2.008s (~)0.806s151.00x
💻 LocalExpress1.414s (-2.1%)2.007s (~)0.593s151.18x
💻 LocalNitro1.425s (+1.3%)2.007s (~)0.582s151.19x
💻 LocalNext.js (Turbopack)1.458s (+3.6%)2.007s (~)0.549s151.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.058s (-10.0% 🟢)4.046s (+12.3% 🔺)1.987s81.00x
▲ VercelExpress2.129s (-6.3% 🟢)3.832s (-1.8%)1.704s81.03x
▲ VercelNext.js (Turbopack)3.677s (+25.2% 🔺)5.040s (+8.6% 🔺)1.363s61.79x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.309s (-6.4% 🟢)2.222s (-10.1% 🟢)0.913s141.00x
💻 LocalNitro2.389s (+3.0%)3.009s (~)0.620s101.82x
💻 LocalNext.js (Turbopack)2.473s (-0.6%)3.010s (-3.2%)0.537s101.89x
💻 LocalExpress2.491s (-6.2% 🟢)3.009s (-3.2%)0.517s101.90x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.366s (-6.4% 🟢)4.064s (+14.2% 🔺)1.698s81.00x
▲ VercelExpress2.432s (-6.7% 🟢)4.074s (-1.1%)1.642s81.03x
▲ VercelNext.js (Turbopack)4.373s (+31.4% 🔺)5.955s (+21.3% 🔺)1.582s61.85x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.542s (-5.3% 🟢)4.136s (~)2.594s81.00x
💻 LocalNext.js (Turbopack)2.942s (-37.4% 🟢)4.442s (-19.4% 🟢)1.500s71.91x
💻 LocalNitro4.604s (+7.2% 🔺)5.515s (+13.2% 🔺)0.910s62.99x
💻 LocalExpress4.804s (+8.8% 🔺)5.345s (+3.2%)0.541s63.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.779s (-1.8%)4.829s (+7.1% 🔺)2.050s71.00x
▲ VercelExpress2.978s (+2.0%)4.815s (+9.6% 🔺)1.837s71.07x
▲ VercelNext.js (Turbopack)4.742s (+20.0% 🔺)6.242s (+8.1% 🔺)1.500s51.71x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.179s (-1.5%)2.008s (~)0.829s151.00x
💻 LocalNitro1.437s (+1.6%)2.007s (~)0.570s151.22x
💻 LocalExpress1.452s (~)2.007s (~)0.555s151.23x
💻 LocalNext.js (Turbopack)1.522s (+1.4%)2.008s (~)0.486s151.29x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.055s (+6.3% 🔺)3.862s (+5.7% 🔺)1.807s81.00x
▲ VercelNitro2.153s (+13.4% 🔺)3.930s (+17.5% 🔺)1.778s81.05x
▲ VercelNext.js (Turbopack)3.867s (+30.1% 🔺)5.350s (+13.7% 🔺)1.483s61.88x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.294s (-1.9%)2.316s (+15.4% 🔺)1.022s131.00x
💻 LocalNitro2.601s (+6.5% 🔺)3.010s (~)0.409s102.01x
💻 LocalExpress2.608s (+4.8%)3.110s (+3.4%)0.502s102.02x
💻 LocalNext.js (Turbopack)2.737s (-2.6%)3.009s (-10.0% 🟢)0.272s102.12x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.427s (-21.7% 🟢)4.164s (-9.0% 🟢)1.737s81.00x
▲ VercelNitro2.715s (+23.6% 🔺)4.460s (+27.2% 🔺)1.746s71.12x
▲ VercelNext.js (Turbopack)3.706s (+17.5% 🔺)5.007s (+10.3% 🔺)1.300s61.53x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.576s (-3.6%)4.011s (-6.7% 🟢)2.435s81.00x
💻 LocalExpress5.357s (+50.2% 🔺)6.214s (+24.0% 🔺)0.857s53.40x
💻 LocalNitro5.624s (+1.8%)6.015s (~)0.392s53.57x
💻 LocalNext.js (Turbopack)5.759s (+6.5% 🔺)6.418s (+6.8% 🔺)0.659s53.65x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.839s (+11.5% 🔺)4.916s (+29.2% 🔺)2.076s71.00x
▲ VercelExpress3.410s (+28.1% 🔺)5.027s (+13.3% 🔺)1.617s61.20x
▲ VercelNext.js (Turbopack)4.339s (-3.8%)6.148s (~)1.809s51.53x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.600s (~)1.041s (+1.7%)0.442s581.00x
💻 LocalNitro0.610s (+4.4%)1.005s (~)0.395s601.02x
💻 LocalExpress0.624s (+3.0%)1.022s (+1.7%)0.399s591.04x
💻 LocalNext.js (Turbopack)0.728s (+21.5% 🔺)1.023s (+1.8%)0.295s591.21x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.688s (+3.2%)4.312s (+7.5% 🔺)1.624s151.00x
▲ VercelExpress2.717s (+9.2% 🔺)4.414s (+11.2% 🔺)1.697s141.01x
▲ VercelNext.js (Turbopack)3.979s (-1.8%)5.460s (-3.5%)1.481s111.48x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.209s (-13.2% 🟢)2.008s (-1.1%)0.798s451.00x
💻 LocalExpress1.512s (+1.2%)2.006s (~)0.495s451.25x
💻 LocalNitro1.535s (+6.1% 🔺)2.006s (~)0.471s451.27x
💻 LocalNext.js (Turbopack)1.709s (+8.6% 🔺)2.007s (~)0.297s451.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.321s (+8.2% 🔺)8.024s (+8.7% 🔺)1.703s121.00x
▲ VercelExpress6.554s (+12.6% 🔺)8.335s (+11.4% 🔺)1.781s111.04x
▲ VercelNext.js (Turbopack)8.643s (+4.8%)10.042s (+4.7%)1.399s101.37x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.672s (-6.1% 🟢)3.192s (-0.8%)0.520s381.00x
💻 LocalExpress3.321s (~)4.009s (~)0.688s301.24x
💻 LocalNitro3.368s (+6.0% 🔺)4.043s (+2.5%)0.675s301.26x
💻 LocalNext.js (Turbopack)3.766s (+9.8% 🔺)4.144s (+3.4%)0.378s301.41x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.319s (+5.4% 🔺)14.027s (+1.4%)1.707s91.00x
▲ VercelNitro13.548s (+17.9% 🔺)15.518s (+20.0% 🔺)1.971s81.10x
▲ VercelNext.js (Turbopack)17.303s (+0.9%)18.740s (~)1.438s71.40x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.210s (-4.8%)1.006s (~)0.795s601.00x
💻 LocalNitro0.523s (+2.2%)1.005s (~)0.482s602.49x
💻 LocalExpress0.606s (+17.3% 🔺)1.039s (+3.4%)0.434s582.88x
💻 LocalNext.js (Turbopack)0.728s (+13.3% 🔺)1.022s (~)0.294s593.46x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.148s (+2.0%)2.715s (+3.3%)1.567s231.00x
▲ VercelNitro1.215s (+10.8% 🔺)2.857s (+19.0% 🔺)1.643s211.06x
▲ VercelNext.js (Turbopack)2.173s (+11.0% 🔺)3.410s (+1.5%)1.237s181.89x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.329s (-6.0% 🟢)1.006s (~)0.677s901.00x
💻 LocalNitro2.521s (~)3.043s (+1.1%)0.522s307.66x
💻 LocalExpress2.555s (+1.0%)3.044s (~)0.489s307.76x
💻 LocalNext.js (Turbopack)2.752s (~)3.077s (-2.2%)0.325s308.36x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.371s (-3.8%)2.931s (-3.9%)1.560s311.00x
▲ VercelNitro1.402s (+6.0% 🔺)2.882s (+15.8% 🔺)1.481s321.02x
▲ VercelNext.js (Turbopack)2.875s (+11.0% 🔺)4.427s (+9.0% 🔺)1.552s212.10x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.553s (-3.6%)1.160s (+7.7% 🔺)0.607s1041.00x
💻 LocalExpress5.138s (-14.1% 🟢)8.157s (-3.9%)3.019s159.29x
💻 LocalNitro5.141s (-12.2% 🟢)8.811s (+1.4%)3.671s149.30x
💻 LocalNext.js (Turbopack)6.644s (+3.3%)9.643s (+4.3%)2.999s1312.02x
🐘 PostgresExpress⚠️missing----
🐘 PostgresNext.js (Turbopack)⚠️missing----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express1.832s (+14.2% 🔺)3.682s (+1.2%)1.849s331.00x
▲ VercelNitro1.861s (+11.7% 🔺)3.866s (+9.2% 🔺)2.006s321.02x
▲ VercelNext.js (Turbopack)3.980s (-5.3% 🟢)5.511s (-3.8%)1.531s222.17x

🔍 Observability: Express | Nitro | Next.js (Turbopack)

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.145s (-1.5%)2.000s (~)0.001s (-16.7% 🟢)2.011s (~)0.866s101.00x
💻 LocalNext.js (Turbopack)1.163s (+2.1%)1.963s (~)0.013s (+30.1% 🔺)2.022s (~)0.859s101.02x
💻 LocalExpress1.165s (~)2.004s (~)0.012s (+5.3% 🔺)2.019s (~)0.854s101.02x
💻 LocalNitro1.166s (+0.9%)2.005s (~)0.013s (+21.9% 🔺)2.021s (~)0.855s101.02x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.063s (+8.2% 🔺)3.682s (+24.3% 🔺)5.347s (+190.7% 🔺)9.559s (+83.1% 🔺)7.496s101.00x
▲ VercelExpress2.078s (+9.9% 🔺)3.546s (+9.5% 🔺)5.423s (+231.1% 🔺)9.486s (+77.4% 🔺)7.407s101.01x
▲ VercelNext.js (Turbopack)3.838s (+20.4% 🔺)4.391s (+25.5% 🔺)5.361s (+268.2% 🔺)10.975s (+70.5% 🔺)7.137s101.86x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.537s (-5.7% 🟢)2.004s (~)0.006s (+6.4% 🔺)2.027s (~)0.490s301.00x
💻 LocalNitro1.579s (~)2.009s (-1.5%)0.013s (-2.2%)2.026s (-1.6%)0.446s301.03x
💻 LocalExpress1.581s (~)2.039s (+1.4%)0.012s (+3.9%)2.059s (+1.7%)0.478s301.03x
💻 LocalNext.js (Turbopack)1.684s (+5.2% 🔺)1.967s (~)0.014s (+14.1% 🔺)2.030s (~)0.346s301.10x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro5.558s (-2.3%)7.654s (+16.1% 🔺)0.194s (-16.6% 🟢)8.385s (+13.1% 🔺)2.827s81.00x
▲ VercelExpress5.710s (+5.2% 🔺)7.460s (+5.8% 🔺)0.096s (-57.0% 🟢)8.025s (+3.2%)2.316s81.03x
▲ VercelNext.js (Turbopack)9.376s (-1.4%)10.558s (~)1.070s (+389.3% 🔺)12.346s (+6.9% 🔺)2.970s51.69x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.765s (-9.7% 🟢)1.044s (-7.0% 🟢)0.000s (+174.1% 🔺)1.060s (-7.2% 🟢)0.295s581.00x
💻 LocalExpress1.334s (-1.5%)1.949s (+1.6%)0.000s (+80.6% 🔺)1.952s (+1.6%)0.618s311.74x
💻 LocalNitro1.334s (-1.1%)1.982s (+1.7%)0.000s (+33.3% 🔺)1.985s (+1.7%)0.651s311.74x
💻 LocalNext.js (Turbopack)1.490s (+6.4% 🔺)1.975s (~)0.001s (-5.3% 🟢)2.018s (~)0.528s301.95x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro2.983s (-27.4% 🟢)5.018s (-4.5%)0.000s (+Infinity% 🔺)5.529s (-3.4%)2.546s111.00x
▲ VercelExpress3.326s (-36.4% 🟢)4.680s (-29.3% 🟢)0.000s (-100.0% 🟢)5.361s (-24.9% 🟢)2.035s121.11x
▲ VercelNext.js (Turbopack)4.895s (+8.8% 🔺)5.805s (+7.4% 🔺)0.000s (+Infinity% 🔺)6.619s (+7.2% 🔺)1.724s101.64x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

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

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.884s (+5.8% 🔺)2.606s (+7.8% 🔺)0.000s (NaN%)2.619s (+7.6% 🔺)0.735s231.00x
💻 LocalExpress3.280s (-1.2%)3.901s (~)0.001s (+500.0% 🔺)3.906s (~)0.625s161.74x
💻 LocalNitro3.288s (+1.4%)3.901s (~)0.001s (-20.0% 🟢)3.904s (~)0.616s161.75x
💻 LocalNext.js (Turbopack)3.901s (+12.8% 🔺)4.349s (+9.0% 🔺)0.001s (-18.1% 🟢)4.394s (+9.0% 🔺)0.493s142.07x
🐘 PostgresExpress⚠️missing-----
🐘 PostgresNext.js (Turbopack)⚠️missing-----

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.575s (+5.2% 🔺)6.251s (+19.0% 🔺)0.000s (NaN%)6.807s (+20.2% 🔺)2.233s91.00x
▲ VercelExpress4.731s (+5.4% 🔺)6.054s (+6.3% 🔺)0.000s (NaN%)6.638s (+7.7% 🔺)1.907s101.03x
▲ VercelNext.js (Turbopack)7.108s (-3.4%)7.730s (-1.0%)0.000s (NaN%)8.799s (-1.6%)1.691s71.55x

🔍 Observability: Nitro | Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress11/21
🐘 PostgresNitro21/21
▲ VercelNitro13/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express💻 Local15/21
Next.js (Turbopack)💻 Local19/21
Nitro🐘 Postgres19/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)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)
  • 🌐 Platformatic: Community world (local development)

📋 View full workflow run

@VaguelySeriousVaguelySerious 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.

workflow-web preview doesn't load runs on this PR, but did on #2752

@VaguelySerious

Copy link
Copy Markdown
Member

^ actually seems to have broken some other commit, ignore

@VaguelySeriousVaguelySerious 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.

It'd be nice if we could unify the logic here between CLI/web since it'll invariable create drift, but otherwise LGTM

@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.

Reviewed and validated the fix live. Approving.

Bug confirmed reproducible: I ran the web dev server on this branch against a local-world project (WORKFLOW_TARGET_WORLD=local, WORKFLOW_OBSERVABILITY_CWD pointed at a project dir), then swapped in main's version of workflow-server-actions.server.ts — main fails every RPC with exactly the static-injection error from the description, this branch returns successful responses. Also exercised the dynamic-resolution error path (WORKFLOW_TARGET_WORLD=@acme/world-missing) and got the clear "Make sure the package is installed in the inspected project" message.

Correctness checks:

  • The env dance holds together: ensureLocalWorldDataDirEnv() still runs before construction and before the WORKFLOW_*-derived cache key is computed, and @workflow/world-local's createWorld() reads WORKFLOW_LOCAL_DATA_DIR — so the arg-less createLocalWorld() call picks up the inspected project's data dir, matching the CLI.
  • The dynamic path is a faithful mirror of the CLI's createPostgresCliWorld() (createRequire(join(cwd, 'package.json')).resolve + import(pathToFileURL(...))), generalized to any backend id — which correctly restores pre-#2752 community-world support for the web UI. @workflow/world-postgres is "type": "module", so the named createWorld export resolves without interop concerns.
  • No remaining call sites of the core stub in packages/web; @workflow/world-local properly added to dependencies with lockfile update; changeset present and accurate (patch).
  • 85/85 web tests pass locally.

CI: 101 pass; the 2 fails are the nextjs-webpack canary HMR fuzz timeout (hmrFuzzAddedStep manifest wait) and its downstream required-check aggregator — a known flaky lane, and this PR touches only web server actions, nothing in the Next integration or manifest rebuild path.

Two non-blocking thoughts:

  1. For community worlds shipped as CJS, import()'s named-export detection depends on cjs-module-lexer; a mod.createWorld ?? mod.default?.createWorld fallback would make the dynamic path a bit more forgiving. The CLI has the same shape today, so fine to defer or do both together.
  2. The CLI's world setup now lags this implementation — it hard-throws on backends other than vercel/postgres/local, while this generalizes to any package exporting createWorld(). A follow-up unifying both on a shared helper (this version) would fix that asymmetry and remove the duplication.

karthikscale3 added a commit that referenced this pull request Jul 7, 2026
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: import() of a require-resolved CJS entry relies on
cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails. Mirrored in the CLI in #2806.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@karthikscale3

Copy link
Copy Markdown
ContributorAuthor

Addressed the review feedback:

@karthikscale3
karthikscale3 merged commit cdfac39 into mainJul 7, 2026
177 of 184 checks passed
@karthikscale3
karthikscale3 deleted the karthik/web-fix-local-world-static-injection branch July 7, 2026 22:47
karthikscale3 added a commit that referenced this pull request Jul 7, 2026
* cli: restore dynamic world loading for community backends
Since #2752 moved world selection to static injection, setupCliWorld only
constructed the vercel, local, and postgres worlds explicitly and threw
'Unsupported workflow backend' for anything else — breaking community
worlds (e.g. @workflow-worlds/turso) that previously loaded through the
dynamic createWorld() in @workflow/core/runtime.
Generalize the postgres-only dynamic path: any backend other than
vercel/local is now resolved from the user's project directory and loaded
via its createWorld() export, matching @workflow/web's world construction
(#2804), with clear errors when the package is missing or does not export
createWorld().
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* cli: fall back to default.createWorld for CJS world packages
Review feedback on #2804: import() of a require-resolved CJS entry relies
on cjs-module-lexer to surface named exports; fall back to
mod.default.createWorld when detection fails.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update .changeset/cli-generic-world-backends.md
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
---------
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for cdfac39 (AI decision).

This commit works around the static-injection createWorld() stub introduced on main by #2752. On stable, createWorld() in packages/core/src/runtime/world.ts is still the older dynamic-selection implementation that resolves worlds at runtime, so the bug being fixed does not exist there and applying this change would be unnecessary (and could regress the working behavior).

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

cdfac39e07e2d15c95f7ab9ff8d244b8677931bd

@github-actionsgithub-actionsBot mentioned this pull request Jul 7, 2026
VaguelySerious added a commit that referenced this pull request Jul 29, 2026
This reverts the static world-target injection and restores runtime
resolution of the world package from `WORKFLOW_TARGET_WORLD`.
Because 141 commits have landed on top of #2752, this is a surgical
revert rather than a mechanical one. Removed: the `world-target` modules
in core/builders/utils, the bundler aliases and `define`s wired through
next/nitro/nuxt/astro/sveltekit/rollup/nest, the
`@workflow/core/runtime/world-target` export, and the
pg-native/node-compat-banner helpers that only existed to support the
statically bundled world.
Kept (later work that builds on #2752):
- `createWorldFromModule` / `WorldFactoryModule` in core (used by
world-testing and the nitro dev handler)
- `world-init` / `world-init-stub` / `getWorldLazy` and their
registration of `getWorld` on globalThis, plus the #3001 isolated
route bundle regression test
- #2804 (web), #2806 (cli dynamic community backends), #3112 (world
factory alias removal), #2988 (nest vercel builder), #2925/#2908
(nitro), #2799 (sveltekit typescript stub is dropped with the
injection it existed for), next basePath support, and the windows /
canary test timeout tuning
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@karthikscale3@VaguelySerious@TooTallNate