Skip to content

[RFC] feat(nitro): embed observability dashboard in-process at /_workflow#2548

Draft
pranaygp wants to merge 1 commit into
mainfrom
pgp/nitro-web-integration
Draft

[RFC] feat(nitro): embed observability dashboard in-process at /_workflow#2548
pranaygp wants to merge 1 commit into
mainfrom
pgp/nitro-web-integration

Conversation

@pranaygp

Copy link
Copy Markdown
Contributor

Context

Using Workflow with a Nitro-based framework (Nitro v2/v3, Nuxt) used to run the local observability UI as a separate process: the dev-only /_workflow handler booted the entire @workflow/web Express server on a random port and 302-redirected to it. That second server, second port, and cross-origin redirect is what this PR eliminates.

Now the dashboard is served in-process, on the same origin/port, at a configurable route (default /_workflow) — no second server, no redirect, no orphan process.

This is the first half of making @workflow/nitro an all-in-one integration. The other half — auto-starting the world on boot — is a follow-up PR that builds on #2544 (ensureWorldStarted) and is intentionally not included here.

Changes

  • @workflow/web — new framework-neutral @workflow/web/handler export (createWorkflowWebHandler({ basename })) that serves SSR + static client assets + RPC as a single Web RequestResponse handler under a runtime mount path. The React Router build (Vite base /) is reprefixed at runtime — asset-manifest URLs + publicPath — so the dashboard is self-contained under its mount (<basename>/assets/...), never touching the host app's root namespace. Adds @workflow/web/registry (best-effort discovery) and makes the RPC/stream client basename-aware. The standalone @workflow/web/server (CLI at /) is unchanged.
  • @workflow/nitroaddDashboardHandler now mounts that handler in-process (Nitro v2 h3.fromWebHandler + v3 native paths) instead of redirecting. New dashboard?: boolean | { enabled?, path? } option; default = on in dev, off in prod. When disabled nothing is registered, so production bundles carry no @workflow/web import (zero bundle/startup cost). Excluded on Vercel deploys.
  • @workflow/cliworkflow web / inspect --web detect an already-running embedded dashboard (via the registry, health-checked) and open it instead of spawning a redundant server on :3456. --standalone forces the standalone UI.

Because the embedded data layer shares the host process's process.env, it reads the same world as the running app automatically (no extra wiring).

Test plan

Verified manually across all three targets + prod gating + CLI:

Check Result
workbench/nitro-v3 (v3 native) /_workflow 200 HTML, assets reprefixed to /_workflow/assets/… + served text/javascript, RPC success:true
workbench/nitro-v2 (v2 h3) 200, UI + assets + RPC all working
workbench/nuxt (Vite SSR) 200, UI + assets; deep-link /_workflow/run/x served by the handler (no SPA-fallback issue)
No second port / orphan only the app's port listens; registry isolates per-pid
Prod build (default) /_workflow serves the app's own index.html; no @workflow/web in the bundle
CLI coordination detects embedded URL; --standalone bypasses
Automated @workflow/web + @workflow/nitro unit tests pass; Biome clean

Follow-up (separate PR, not here)

Auto-start the world on server boot via a Nitro plugin (ensureWorldStarted), gated off Vercel — depends on #2544 merging first.

🤖 Generated with Claude Code

Serve the @workflow/web observability UI inside the Nitro process at a
configurable route (default /_workflow) instead of spawning a separate
web server and 302-redirecting to it. Enabled in dev, omitted from
production builds by default (so prod bundles carry no @workflow/web
import). Never mounted on Vercel deploys (use the hosted dashboard).

- @workflow/web: add a framework-neutral `@workflow/web/handler`
  (createWorkflowWebHandler) that serves SSR + static client assets +
  RPC as one Web Request->Response handler under a runtime basename
  (asset manifest URLs + publicPath are reprefixed so the dashboard is
  self-contained under its mount). Add `@workflow/web/registry` for
  embedded-dashboard discovery; make the RPC/stream client basename-aware.
- @workflow/nitro: mount the handler in-process (Nitro v2 h3 + v3 native
  paths), gated by a new `dashboard` option (default = dev).
- @workflow/cli: `workflow web` / `inspect --web` defer to a running
  embedded dashboard instead of starting a redundant server; pass
  `--standalone` to force the standalone UI.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@pranaygp pranaygp requested a review from a team as a code owner June 20, 2026 21:20
Copilot AI review requested due to automatic review settings June 20, 2026 21:20
@changeset-bot

changeset-bot Bot commented Jun 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4ba2a5a

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

This PR includes changesets to release 16 packages
Name Type
@workflow/cli Minor
@workflow/nitro Minor
@workflow/web Minor
workflow Patch
@workflow/world-testing Patch
@workflow/nuxt Patch
@workflow/core Patch
@workflow/web-shared Minor
@workflow/builders Patch
@workflow/next Patch
@workflow/vitest Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch

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

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

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

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

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

workflow with no steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 0.031s (-25.4% 🟢) 1.004s (~) 0.974s 10 1.00x
💻 Local Express 0.042s (+0.7%) 1.006s (~) 0.964s 10 1.36x
💻 Local Next.js (Turbopack) 0.045s (-6.7% 🟢) 1.006s (~) 0.961s 10 1.47x
🐘 Postgres Next.js (Turbopack) 0.055s (-5.5% 🟢) 1.011s (~) 0.956s 10 1.79x
🐘 Postgres Express 0.061s (-0.8%) 1.012s (~) 0.951s 10 2.00x
🐘 Postgres Nitro 0.069s (+9.2% 🔺) 1.013s (~) 0.944s 10 2.26x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 0.320s (-18.0% 🟢) 2.613s (+3.3%) 2.293s 10 1.00x
▲ Vercel Next.js (Turbopack) 0.336s (+3.8%) 2.367s (-15.1% 🟢) 2.032s 10 1.05x
▲ Vercel Express 0.348s (-12.4% 🟢) 2.298s (-5.7% 🟢) 1.950s 10 1.09x

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

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.069s (-1.8%) 2.005s (~) 0.936s 10 1.00x
💻 Local Next.js (Turbopack) 1.087s (~) 2.007s (~) 0.920s 10 1.02x
💻 Local Express 1.091s (-0.8%) 2.006s (~) 0.915s 10 1.02x
🐘 Postgres Next.js (Turbopack) 1.093s (-0.8%) 2.010s (~) 0.917s 10 1.02x
🐘 Postgres Express 1.101s (~) 2.010s (~) 0.909s 10 1.03x
🐘 Postgres Nitro 1.125s (+1.9%) 2.012s (~) 0.887s 10 1.05x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 1.666s (+5.5% 🔺) 3.358s (-9.6% 🟢) 1.692s 10 1.00x
▲ Vercel Express 1.672s (+9.9% 🔺) 3.596s (+0.8%) 1.924s 10 1.00x
▲ Vercel Nitro 1.684s (+9.3% 🔺) 3.725s (+6.1% 🔺) 2.041s 10 1.01x

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

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 10.405s (-1.0%) 11.021s (~) 0.616s 3 1.00x
💻 Local Express 10.507s (~) 11.023s (~) 0.516s 3 1.01x
💻 Local Next.js (Turbopack) 10.508s (~) 11.024s (~) 0.516s 3 1.01x
🐘 Postgres Express 10.513s (~) 11.015s (~) 0.502s 3 1.01x
🐘 Postgres Next.js (Turbopack) 10.525s (~) 11.017s (~) 0.492s 3 1.01x
🐘 Postgres Nitro 10.612s (+0.6%) 11.024s (~) 0.411s 3 1.02x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 12.858s (~) 15.117s (-1.0%) 2.259s 2 1.00x
▲ Vercel Express 13.328s (+1.8%) 15.205s (~) 1.877s 2 1.04x
▲ Vercel Next.js (Turbopack) 13.378s (+1.4%) 14.620s (-4.9%) 1.243s 3 1.04x

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

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 13.468s (-1.6%) 14.025s (~) 0.557s 5 1.00x
💻 Local Next.js (Turbopack) 13.623s (-0.6%) 14.028s (~) 0.405s 5 1.01x
💻 Local Express 13.708s (-2.0%) 14.028s (-1.4%) 0.319s 5 1.02x
🐘 Postgres Express 13.727s (~) 14.020s (~) 0.293s 5 1.02x
🐘 Postgres Next.js (Turbopack) 13.863s (~) 14.019s (~) 0.155s 5 1.03x
🐘 Postgres Nitro 13.895s (~) 14.023s (~) 0.128s 5 1.03x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 20.238s (~) 22.676s (+1.1%) 2.438s 3 1.00x
▲ Vercel Next.js (Turbopack) 21.320s (+6.9% 🔺) 23.122s (+4.1%) 1.802s 3 1.05x
▲ Vercel Nitro 21.471s (~) 23.459s (~) 1.987s 3 1.06x

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

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 11.790s (-4.1%) 12.020s (-7.7% 🟢) 0.230s 8 1.00x
💻 Local Next.js (Turbopack) 12.358s (-0.8%) 13.027s (~) 0.669s 7 1.05x
🐘 Postgres Express 12.429s (~) 13.019s (~) 0.590s 7 1.05x
💻 Local Express 12.466s (-1.0%) 13.025s (~) 0.559s 7 1.06x
🐘 Postgres Next.js (Turbopack) 12.744s (+1.7%) 13.303s (+2.2%) 0.559s 7 1.08x
🐘 Postgres Nitro 12.834s (+3.5%) 13.165s (+1.2%) 0.331s 7 1.09x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 25.851s (+4.5%) 28.514s (+6.8% 🔺) 2.663s 4 1.00x
▲ Vercel Express 26.165s (+13.7% 🔺) 28.536s (+13.4% 🔺) 2.371s 4 1.01x
▲ Vercel Next.js (Turbopack) 27.730s (+10.3% 🔺) 29.761s (+8.4% 🔺) 2.031s 4 1.07x

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

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.154s (~) 2.007s (~) 0.853s 15 1.00x
🐘 Postgres Express 1.181s (-1.2%) 2.008s (~) 0.827s 15 1.02x
💻 Local Nitro 1.187s (-1.3%) 2.005s (~) 0.818s 15 1.03x
💻 Local Express 1.195s (-2.9%) 2.006s (~) 0.811s 15 1.04x
🐘 Postgres Nitro 1.211s (+2.0%) 2.010s (~) 0.799s 15 1.05x
💻 Local Next.js (Turbopack) 1.317s (-4.2%) 2.006s (~) 0.690s 15 1.14x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.478s (-8.0% 🟢) 4.129s (-7.4% 🟢) 1.651s 8 1.00x
▲ Vercel Nitro 2.570s (-2.9%) 4.466s (~) 1.896s 7 1.04x
▲ Vercel Next.js (Turbopack) 2.808s (+8.3% 🔺) 4.725s (+6.7% 🔺) 1.917s 7 1.13x

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

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.273s (+1.7%) 2.074s (+3.4%) 0.801s 15 1.00x
🐘 Postgres Express 1.283s (-1.9%) 2.008s (-3.2%) 0.725s 15 1.01x
🐘 Postgres Nitro 1.347s (+6.1% 🔺) 2.009s (~) 0.662s 15 1.06x
💻 Local Nitro 1.728s (-14.2% 🟢) 2.072s (-17.3% 🟢) 0.344s 15 1.36x
💻 Local Express 2.179s (+7.1% 🔺) 2.591s (+3.3%) 0.412s 12 1.71x
💻 Local Next.js (Turbopack) 2.309s (-1.5%) 2.735s (-6.3% 🟢) 0.426s 11 1.81x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.741s (+32.0% 🔺) 5.771s (+25.7% 🔺) 2.030s 6 1.00x
▲ Vercel Next.js (Turbopack) 3.980s (+24.9% 🔺) 5.608s (+9.4% 🔺) 1.628s 6 1.06x
▲ Vercel Nitro 4.124s (+65.8% 🔺) 6.166s (+51.9% 🔺) 2.042s 6 1.10x

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

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.431s (-13.7% 🟢) 3.010s (-20.0% 🟢) 1.579s 10 1.00x
🐘 Postgres Nitro 1.497s (+3.2%) 3.761s (+2.2%) 2.264s 8 1.05x
🐘 Postgres Next.js (Turbopack) 1.528s (+3.1%) 3.677s (-5.4% 🟢) 2.149s 9 1.07x
💻 Local Nitro 3.783s (-15.6% 🟢) 4.438s (-11.4% 🟢) 0.656s 7 2.64x
💻 Local Express 5.259s (-8.9% 🟢) 6.015s (-6.2% 🟢) 0.756s 5 3.68x
💻 Local Next.js (Turbopack) 5.750s (-14.1% 🟢) 6.419s (-13.5% 🟢) 0.669s 5 4.02x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 4.432s (+44.2% 🔺) 6.586s (+34.0% 🔺) 2.153s 5 1.00x
▲ Vercel Next.js (Turbopack) 4.439s (+26.7% 🔺) 6.263s (+15.3% 🔺) 1.824s 5 1.00x
▲ Vercel Express 4.976s (+62.0% 🔺) 6.984s (+41.6% 🔺) 2.008s 5 1.12x

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

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.157s (-1.4%) 2.008s (~) 0.851s 15 1.00x
🐘 Postgres Express 1.179s (-1.4%) 2.007s (~) 0.829s 15 1.02x
💻 Local Nitro 1.182s (-3.8%) 2.005s (~) 0.823s 15 1.02x
🐘 Postgres Nitro 1.222s (+1.9%) 2.009s (~) 0.787s 15 1.06x
💻 Local Express 1.229s (~) 2.006s (~) 0.777s 15 1.06x
💻 Local Next.js (Turbopack) 1.344s (-0.5%) 2.007s (~) 0.663s 15 1.16x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.211s (+2.1%) 3.898s (+0.5%) 1.687s 8 1.00x
▲ Vercel Next.js (Turbopack) 2.474s (+15.7% 🔺) 3.867s (-4.7%) 1.393s 8 1.12x
▲ Vercel Express 2.676s (+32.2% 🔺) 4.392s (+12.5% 🔺) 1.717s 7 1.21x

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

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.252s (-0.9%) 2.008s (-3.2%) 0.756s 15 1.00x
🐘 Postgres Express 1.264s (-2.3%) 2.007s (~) 0.743s 15 1.01x
🐘 Postgres Nitro 1.305s (+2.3%) 2.010s (~) 0.705s 15 1.04x
💻 Local Nitro 1.712s (-14.8% 🟢) 2.072s (-10.5% 🟢) 0.360s 15 1.37x
💻 Local Express 2.104s (+3.2%) 2.315s (-15.4% 🟢) 0.211s 13 1.68x
💻 Local Next.js (Turbopack) 2.452s (+1.4%) 2.826s (-3.1%) 0.374s 11 1.96x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.404s (+31.9% 🔺) 5.237s (+20.5% 🔺) 1.833s 6 1.00x
▲ Vercel Nitro 3.442s (+25.5% 🔺) 5.427s (+26.3% 🔺) 1.986s 6 1.01x
▲ Vercel Next.js (Turbopack) 4.002s (+50.3% 🔺) 6.097s (+46.5% 🔺) 2.095s 5 1.18x

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

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.506s (+3.4%) 3.888s (+3.4%) 2.382s 8 1.00x
🐘 Postgres Next.js (Turbopack) 1.512s (+2.9%) 3.676s (-5.4% 🟢) 2.165s 9 1.00x
🐘 Postgres Express 1.557s (+8.8% 🔺) 3.344s (-11.1% 🟢) 1.788s 9 1.03x
💻 Local Nitro 4.654s (-5.9% 🟢) 5.177s (-6.1% 🟢) 0.523s 6 3.09x
💻 Local Express 5.287s (-11.3% 🟢) 6.015s (-11.7% 🟢) 0.729s 5 3.51x
💻 Local Next.js (Turbopack) 6.240s (-8.1% 🟢) 6.818s (-9.3% 🟢) 0.578s 5 4.14x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 4.281s (-2.8%) 6.539s (~) 2.258s 5 1.00x
▲ Vercel Express 4.680s (+10.0% 🔺) 7.168s (+17.6% 🔺) 2.488s 5 1.09x
▲ Vercel Next.js (Turbopack) 5.762s (+74.3% 🔺) 7.573s (+44.0% 🔺) 1.811s 4 1.35x

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

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 0.465s (-18.5% 🟢) 1.004s (-1.8%) 0.539s 60 1.00x
🐘 Postgres Next.js (Turbopack) 0.513s (-9.4% 🟢) 1.006s (-1.7%) 0.493s 60 1.10x
🐘 Postgres Express 0.546s (-5.3% 🟢) 1.041s (+1.7%) 0.495s 58 1.17x
💻 Local Express 0.561s (-8.1% 🟢) 1.005s (~) 0.444s 60 1.21x
💻 Local Next.js (Turbopack) 0.598s (-2.3%) 1.005s (-1.7%) 0.407s 60 1.29x
🐘 Postgres Nitro 0.625s (+11.2% 🔺) 1.024s (~) 0.400s 59 1.34x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.774s (+25.3% 🔺) 5.645s (+11.8% 🔺) 1.871s 11 1.00x
▲ Vercel Next.js (Turbopack) 3.978s (-3.7%) 5.600s (-10.3% 🟢) 1.622s 11 1.05x
▲ Vercel Express 4.340s (+26.5% 🔺) 6.264s (+15.4% 🔺) 1.924s 10 1.15x

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

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.163s (-15.9% 🟢) 2.005s (~) 0.842s 45 1.00x
🐘 Postgres Next.js (Turbopack) 1.248s (-2.2%) 2.008s (~) 0.760s 45 1.07x
🐘 Postgres Express 1.295s (-2.3%) 2.030s (+1.1%) 0.735s 45 1.11x
🐘 Postgres Nitro 1.424s (+11.7% 🔺) 2.031s (+1.2%) 0.607s 45 1.22x
💻 Local Next.js (Turbopack) 1.467s (-0.6%) 2.006s (~) 0.539s 45 1.26x
💻 Local Express 1.479s (-5.1% 🟢) 2.028s (~) 0.549s 45 1.27x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 7.964s (-7.1% 🟢) 10.049s (-3.6%) 2.084s 10 1.00x
▲ Vercel Nitro 8.394s (+10.0% 🔺) 10.274s (+8.2% 🔺) 1.879s 9 1.05x
▲ Vercel Next.js (Turbopack) 9.277s (+13.3% 🔺) 11.127s (+11.3% 🔺) 1.849s 9 1.16x

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

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 2.451s (-3.9%) 3.009s (~) 0.558s 40 1.00x
🐘 Postgres Express 2.495s (-5.4% 🟢) 3.058s (~) 0.563s 40 1.02x
💻 Local Nitro 2.681s (-10.5% 🟢) 3.057s (-11.1% 🟢) 0.376s 40 1.09x
🐘 Postgres Nitro 2.861s (+7.8% 🔺) 3.164s (+0.9%) 0.303s 39 1.17x
💻 Local Express 3.157s (-2.9%) 3.881s (-3.2%) 0.724s 31 1.29x
💻 Local Next.js (Turbopack) 3.163s (-1.3%) 3.977s (~) 0.814s 31 1.29x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 18.654s (+24.0% 🔺) 21.011s (+22.0% 🔺) 2.357s 6 1.00x
▲ Vercel Nitro 19.293s (+15.5% 🔺) 21.385s (+12.4% 🔺) 2.093s 6 1.03x
▲ Vercel Next.js (Turbopack) 20.845s (+28.7% 🔺) 22.679s (+23.2% 🔺) 1.834s 6 1.12x

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

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 0.159s (-10.9% 🟢) 1.006s (~) 0.847s 60 1.00x
🐘 Postgres Express 0.209s (-4.4%) 1.006s (~) 0.797s 60 1.31x
🐘 Postgres Nitro 0.234s (+10.4% 🔺) 1.007s (~) 0.773s 60 1.47x
💻 Local Nitro 0.275s (-18.4% 🟢) 1.004s (~) 0.729s 60 1.73x
💻 Local Express 0.325s (-4.8%) 1.004s (~) 0.680s 60 2.04x
💻 Local Next.js (Turbopack) 0.613s (+1.3%) 1.022s (+1.7%) 0.408s 59 3.85x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.429s (+12.9% 🔺) 3.093s (+4.6%) 1.664s 20 1.00x
▲ Vercel Nitro 1.528s (+11.7% 🔺) 3.222s (+3.3%) 1.695s 19 1.07x
▲ Vercel Next.js (Turbopack) 1.734s (+31.8% 🔺) 3.358s (+12.9% 🔺) 1.624s 18 1.21x

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

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 0.274s (+2.2%) 1.006s (~) 0.732s 90 1.00x
🐘 Postgres Express 0.314s (-2.1%) 1.017s (+1.1%) 0.703s 89 1.15x
🐘 Postgres Nitro 0.370s (+14.6% 🔺) 1.007s (~) 0.637s 90 1.35x
💻 Local Nitro 1.600s (-21.0% 🟢) 2.030s (-17.8% 🟢) 0.430s 45 5.84x
💻 Local Express 1.991s (+1.8%) 2.495s (+1.1%) 0.503s 37 7.27x
💻 Local Next.js (Turbopack) 2.612s (-2.1%) 3.042s (-1.1%) 0.430s 30 9.53x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.198s (+29.6% 🔺) 4.184s (+16.6% 🔺) 1.987s 22 1.00x
▲ Vercel Express 2.693s (+58.7% 🔺) 4.660s (+31.8% 🔺) 1.967s 20 1.23x
▲ Vercel Next.js (Turbopack) 3.291s (+46.8% 🔺) 4.989s (+19.1% 🔺) 1.698s 19 1.50x

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

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 0.461s (-4.4%) 3.059s (+0.8%) 2.598s 40 1.00x
🐘 Postgres Express 0.521s (+5.7% 🔺) 1.078s (+6.3% 🔺) 0.557s 112 1.13x
🐘 Postgres Nitro 0.583s (+11.2% 🔺) 1.129s (+7.5% 🔺) 0.546s 107 1.27x
💻 Local Nitro 8.246s (-11.9% 🟢) 8.809s (-12.9% 🟢) 0.563s 14 17.90x
💻 Local Next.js (Turbopack) 9.344s (-7.1% 🟢) 10.110s (-9.1% 🟢) 0.766s 12 20.29x
💻 Local Express 9.732s (-0.5%) 10.445s (-1.6%) 0.713s 12 21.13x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.340s (+37.7% 🔺) 5.295s (+21.0% 🔺) 1.955s 23 1.00x
▲ Vercel Nitro 3.997s (+81.4% 🔺) 6.260s (+52.4% 🔺) 2.263s 20 1.20x
▲ Vercel Next.js (Turbopack) 4.768s (+34.5% 🔺) 6.774s (+25.0% 🔺) 2.006s 18 1.43x

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

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.133s (-1.4%) 2.003s (~) 0.008s (-13.0% 🟢) 2.014s (~) 0.881s 10 1.00x
💻 Local Next.js (Turbopack) 1.149s (~) 2.003s (~) 0.010s (-17.7% 🟢) 2.018s (~) 0.869s 10 1.01x
🐘 Postgres Next.js (Turbopack) 1.150s (-1.8%) 1.999s (~) 0.001s (-25.0% 🟢) 2.009s (~) 0.859s 10 1.01x
🐘 Postgres Express 1.161s (-1.4%) 1.997s (~) 0.001s (-35.7% 🟢) 2.010s (~) 0.849s 10 1.02x
💻 Local Express 1.168s (-0.5%) 2.005s (~) 0.010s (-18.7% 🟢) 2.018s (~) 0.850s 10 1.03x
🐘 Postgres Nitro 1.183s (+1.2%) 1.994s (~) 0.002s (-21.1% 🟢) 2.012s (~) 0.829s 10 1.04x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.368s (+9.9% 🔺) 3.654s (+7.1% 🔺) 2.685s (+68.7% 🔺) 6.913s (+23.8% 🔺) 4.545s 10 1.00x
▲ Vercel Next.js (Turbopack) 2.447s (+16.0% 🔺) 3.637s (+7.5% 🔺) 2.674s (+61.1% 🔺) 6.740s (+21.7% 🔺) 4.294s 10 1.03x
▲ Vercel Express 2.579s (+14.2% 🔺) 3.846s (+12.8% 🔺) 2.708s (~) 7.096s (+4.1%) 4.518s 10 1.09x

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

stream pipeline with 5 transform steps (1MB)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.459s (-7.6% 🟢) 2.008s (~) 0.010s (-14.0% 🟢) 2.021s (~) 0.562s 30 1.00x
🐘 Postgres Express 1.570s (-1.0%) 2.006s (~) 0.005s (+6.0% 🔺) 2.025s (~) 0.455s 30 1.08x
🐘 Postgres Next.js (Turbopack) 1.578s (-1.4%) 2.009s (~) 0.005s (+5.4% 🔺) 2.025s (~) 0.447s 30 1.08x
💻 Local Express 1.581s (~) 2.009s (~) 0.013s (+7.3% 🔺) 2.025s (~) 0.445s 30 1.08x
💻 Local Next.js (Turbopack) 1.603s (-1.0%) 2.009s (~) 0.012s (-5.8% 🟢) 2.025s (~) 0.423s 30 1.10x
🐘 Postgres Nitro 1.672s (+1.8%) 2.003s (-1.7%) 0.005s (+10.1% 🔺) 2.028s (-1.5%) 0.356s 30 1.15x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 6.548s (+10.2% 🔺) 7.875s (+3.6%) 0.159s (-51.9% 🟢) 8.502s (~) 1.954s 8 1.00x
▲ Vercel Express 6.708s (+9.4% 🔺) 8.395s (+7.0% 🔺) 0.279s (-1.7%) 9.202s (+6.1% 🔺) 2.494s 7 1.02x
▲ Vercel Nitro 7.034s (+22.9% 🔺) 8.536s (+12.7% 🔺) 0.275s (-11.4% 🟢) 9.393s (+11.5% 🔺) 2.359s 7 1.07x

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

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.763s (~) 1.068s (~) 0.000s (+Infinity% 🔺) 1.079s (~) 0.317s 56 1.00x
🐘 Postgres Next.js (Turbopack) 0.775s (+1.8%) 1.132s (+4.0%) 0.000s (+7.5% 🔺) 1.139s (+3.9%) 0.364s 53 1.02x
🐘 Postgres Nitro 0.827s (+7.5% 🔺) 1.059s (-4.1%) 0.000s (-1.8%) 1.092s (-2.4%) 0.265s 55 1.08x
💻 Local Nitro 1.166s (-14.6% 🟢) 1.946s (-3.3%) 0.000s (-67.7% 🟢) 1.948s (-3.3%) 0.782s 31 1.53x
💻 Local Express 1.397s (+5.7% 🔺) 2.013s (~) 0.000s (-45.5% 🟢) 2.016s (~) 0.619s 30 1.83x
💻 Local Next.js (Turbopack) 1.489s (+2.8%) 2.011s (~) 0.001s (+144.4% 🔺) 2.016s (~) 0.527s 30 1.95x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.625s (-23.7% 🟢) 5.086s (-22.9% 🟢) 0.000s (NaN%) 5.595s (-21.5% 🟢) 1.970s 11 1.00x
▲ Vercel Next.js (Turbopack) 4.000s (-5.4% 🟢) 5.314s (-14.5% 🟢) 0.000s (-100.0% 🟢) 5.736s (-15.8% 🟢) 1.735s 11 1.10x
▲ Vercel Express 4.057s (+20.1% 🔺) 5.599s (+11.0% 🔺) 0.000s (-45.0% 🟢) 6.122s (+10.0% 🔺) 2.064s 10 1.12x

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

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

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.707s (+11.6% 🔺) 2.217s (+5.5% 🔺) 0.000s (-100.0% 🟢) 2.261s (+5.1% 🔺) 0.554s 27 1.00x
🐘 Postgres Next.js (Turbopack) 1.871s (-2.0%) 2.442s (-4.0%) 0.000s (NaN%) 2.450s (-3.9%) 0.579s 25 1.10x
🐘 Postgres Nitro 1.877s (+13.4% 🔺) 2.433s (+9.9% 🔺) 0.000s (+116.0% 🔺) 2.451s (+9.9% 🔺) 0.573s 25 1.10x
💻 Local Nitro 2.746s (-21.6% 🟢) 3.178s (-19.8% 🟢) 0.000s (-62.6% 🟢) 3.189s (-19.7% 🟢) 0.443s 19 1.61x
💻 Local Express 3.576s (-1.8%) 4.093s (-3.2%) 0.002s (+270.0% 🔺) 4.104s (-3.0%) 0.528s 15 2.10x
💻 Local Next.js (Turbopack) 4.420s (+7.3% 🔺) 4.953s (+7.7% 🔺) 0.001s (-46.2% 🟢) 4.958s (+7.6% 🔺) 0.538s 13 2.59x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 6.048s (+6.3% 🔺) 7.855s (+10.0% 🔺) 0.000s (-100.0% 🟢) 8.444s (+9.4% 🔺) 2.396s 8 1.00x
▲ Vercel Express 6.184s (-25.1% 🟢) 8.018s (-18.8% 🟢) 0.000s (-100.0% 🟢) 8.499s (-18.6% 🟢) 2.314s 8 1.02x
▲ Vercel Next.js (Turbopack) 6.405s (+21.0% 🔺) 7.783s (+14.7% 🔺) 0.000s (NaN%) 8.221s (+12.3% 🔺) 1.816s 8 1.06x

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

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Nitro 21/21
🐘 Postgres Next.js (Turbopack) 13/21
▲ Vercel Nitro 11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 🐘 Postgres 17/21
Next.js (Turbopack) 🐘 Postgres 15/21
Nitro 💻 Local 12/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)

📋 View full workflow run

@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 1442 0 230 1672
✅ 💻 Local Development 1909 0 219 2128
✅ 📦 Local Production 1909 0 219 2128
✅ 🐘 Local Postgres 1895 0 233 2128
✅ 🪟 Windows 152 0 0 152
✅ 📋 Other 885 0 179 1064
Total 8192 0 1080 9272

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 125 0 27
✅ example 125 0 27
✅ express 125 0 27
✅ fastify 125 0 27
✅ hono 125 0 27
✅ nextjs-turbopack 149 0 3
✅ nextjs-webpack 149 0 3
✅ nitro 125 0 27
✅ nuxt 125 0 27
✅ sveltekit 144 0 8
✅ vite 125 0 27
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 127 0 25
✅ express-stable 127 0 25
✅ fastify-stable 127 0 25
✅ hono-stable 127 0 25
✅ nextjs-turbopack-canary 133 0 19
✅ nextjs-turbopack-stable-lazy-discovery-disabled 152 0 0
✅ nextjs-turbopack-stable-lazy-discovery-enabled 152 0 0
✅ nextjs-webpack-canary 133 0 19
✅ nextjs-webpack-stable-lazy-discovery-disabled 152 0 0
✅ nextjs-webpack-stable-lazy-discovery-enabled 152 0 0
✅ nitro-stable 127 0 25
✅ nuxt-stable 127 0 25
✅ sveltekit-stable 146 0 6
✅ vite-stable 127 0 25
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 127 0 25
✅ express-stable 127 0 25
✅ fastify-stable 127 0 25
✅ hono-stable 127 0 25
✅ nextjs-turbopack-canary 133 0 19
✅ nextjs-turbopack-stable-lazy-discovery-disabled 152 0 0
✅ nextjs-turbopack-stable-lazy-discovery-enabled 152 0 0
✅ nextjs-webpack-canary 133 0 19
✅ nextjs-webpack-stable-lazy-discovery-disabled 152 0 0
✅ nextjs-webpack-stable-lazy-discovery-enabled 152 0 0
✅ nitro-stable 127 0 25
✅ nuxt-stable 127 0 25
✅ sveltekit-stable 146 0 6
✅ vite-stable 127 0 25
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 126 0 26
✅ express-stable 126 0 26
✅ fastify-stable 126 0 26
✅ hono-stable 126 0 26
✅ nextjs-turbopack-canary 132 0 20
✅ nextjs-turbopack-stable-lazy-discovery-disabled 151 0 1
✅ nextjs-turbopack-stable-lazy-discovery-enabled 151 0 1
✅ nextjs-webpack-canary 132 0 20
✅ nextjs-webpack-stable-lazy-discovery-disabled 151 0 1
✅ nextjs-webpack-stable-lazy-discovery-enabled 151 0 1
✅ nitro-stable 126 0 26
✅ nuxt-stable 126 0 26
✅ sveltekit-stable 145 0 7
✅ vite-stable 126 0 26
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 152 0 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 127 0 25
✅ e2e-local-dev-tanstack-start- 127 0 25
✅ e2e-local-postgres-nest-stable 126 0 26
✅ e2e-local-postgres-tanstack-start- 126 0 26
✅ e2e-local-prod-nest-stable 127 0 25
✅ e2e-local-prod-tanstack-start- 127 0 25
✅ e2e-vercel-prod-tanstack-start 125 0 27

📋 View full workflow run

@pranaygp pranaygp changed the title feat(nitro): embed observability dashboard in-process at /_workflow [RFC] feat(nitro): embed observability dashboard in-process at /_workflow Jun 20, 2026
@pranaygp pranaygp marked this pull request as draft June 20, 2026 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants