Skip to content

Add workflow analytics world APIs#2234

Merged
karthikscale3 merged 4 commits into
mainfrom
codex/workflow-analytics-apis
Jul 1, 2026
Merged

Add workflow analytics world APIs#2234
karthikscale3 merged 4 commits into
mainfrom
codex/workflow-analytics-apis

Conversation

@karthikscale3

@karthikscale3 karthikscale3 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

What changed

Adds a new optional, metadata-only world.analytics.* namespace for workflow observability reads.

  • Adds analytics schemas and types in @workflow/world
  • Adds an optional analytics?: Analytics to the World interface
  • Adds createAnalytics() in @workflow/world-vercel
  • Wires createVercelWorld() to expose world.analytics
  • Adds a changeset for @workflow/world and @workflow/world-vercel

Why

This gives observability surfaces (CLI, dashboards) an explicit, read-only
metadata surface for listing and trace views, separate from the canonical
runtime storage APIs. Payloads, RemoteRef resolution, inputs, outputs, and
error hydration remain on the existing runtime APIs (runs, steps,
events, hooks).

analytics is optional on the World interface: backends that do not
provide a metadata read path simply leave it unset, and consumers fall
back to the runtime storage APIs.

API surface

world.analytics exposes read-only list/get for:

  • runs — list (filter by workflowName, status) and get by id
  • steps — list per run and get by id
  • events — list per run, list by correlationId, and get by id
  • hooks — list (optionally per run) and get by id
  • waits — list per run (filter by status) and get by id

All return metadata only (ids, status, timestamps, names, error codes,
flags) — no payload-bearing fields.

Validation

  • pnpm --filter @workflow/world exec tsc --noEmit --pretty false
  • pnpm --filter @workflow/world-vercel exec tsc --noEmit --pretty false
  • pnpm exec biome check packages/world/src/analytics.ts packages/world/src/interfaces.ts packages/world/src/index.ts packages/world-vercel/src/analytics.ts packages/world-vercel/src/index.ts

Merge order

This work lands as a stack of four PRs on the world.analytics read-path:

  1. Add workflow analytics world APIs #2234 — add the optional world.analytics namespace (base main) — merge first
  2. cli: read list views from world.analytics when available #2648 — CLI list reads via world.analytics (stacked on Add workflow analytics world APIs #2234)
  3. web: read observability list views from world.analytics when available #2647 — web list reads (runs/steps/events) via world.analytics (stacked on Add workflow analytics world APIs #2234)
  4. web: list hooks from analytics, fetch token on demand #2652 — web lazy hook-token fetch (stacked on web: read observability list views from world.analytics when available #2647) — merge after web: read observability list views from world.analytics when available #2647

#2648 and #2647 both depend only on #2234 and are independent of each other. #2652 builds on #2647. After #2234 merges to main, the stacked PRs auto-retarget.

@changeset-bot

changeset-bot Bot commented Jun 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7e9fc67

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

This PR includes changesets to release 20 packages
Name Type
@workflow/world Minor
@workflow/world-vercel Minor
@workflow/cli Patch
@workflow/core Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/web Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/world-testing Patch
workflow Patch
@workflow/builders Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt 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 3, 2026

Copy link
Copy Markdown
Contributor

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

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

@github-actions

github-actions Bot commented Jun 3, 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 🥇 Next.js (Turbopack) 0.043s (-19.3% 🟢) 1.005s (~) 0.961s 10 1.00x
💻 Local Express 0.045s (-1.9%) 1.006s (~) 0.960s 10 1.04x
💻 Local Nitro 0.048s (+8.2% 🔺) 1.006s (~) 0.958s 10 1.10x
🐘 Postgres Next.js (Turbopack) 0.060s (-45.2% 🟢) 1.012s (-2.7%) 0.951s 10 1.39x
🐘 Postgres Express 0.062s (-15.3% 🟢) 1.012s (~) 0.951s 10 1.43x
🐘 Postgres Nitro 0.071s (+13.2% 🔺) 1.013s (~) 0.941s 10 1.64x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 0.239s (+18.2% 🔺) 1.375s (-30.4% 🟢) 1.136s 10 1.00x
▲ Vercel Nitro 0.276s (-24.5% 🟢) 1.595s (-12.9% 🟢) 1.320s 10 1.15x
▲ Vercel Next.js (Turbopack) 0.654s (+41.5% 🔺) 2.666s (+3.9%) 2.012s 10 2.74x

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

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 1.067s (-1.3%) 2.006s (~) 0.939s 10 1.00x
💻 Local Express 1.079s (~) 2.006s (~) 0.927s 10 1.01x
💻 Local Nitro 1.085s (~) 2.007s (~) 0.922s 10 1.02x
🐘 Postgres Express 1.095s (~) 2.009s (~) 0.915s 10 1.03x
🐘 Postgres Next.js (Turbopack) 1.098s (~) 2.009s (~) 0.911s 10 1.03x
🐘 Postgres Nitro 1.110s (+1.6%) 2.012s (~) 0.902s 10 1.04x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.444s (+6.0% 🔺) 2.783s (+5.7% 🔺) 1.339s 10 1.00x
▲ Vercel Nitro 1.451s (+7.8% 🔺) 2.996s (+5.9% 🔺) 1.545s 10 1.00x
▲ Vercel Next.js (Turbopack) 2.388s (+6.4% 🔺) 3.925s (+2.8%) 1.537s 10 1.65x

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

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 10.376s (-1.0%) 11.021s (~) 0.645s 3 1.00x
💻 Local Express 10.439s (~) 11.023s (~) 0.583s 3 1.01x
🐘 Postgres Express 10.457s (~) 11.020s (~) 0.563s 3 1.01x
💻 Local Nitro 10.476s (~) 11.022s (~) 0.546s 3 1.01x
🐘 Postgres Next.js (Turbopack) 10.499s (+1.0%) 11.014s (~) 0.515s 3 1.01x
🐘 Postgres Nitro 10.518s (+0.5%) 11.021s (~) 0.503s 3 1.01x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 11.679s (-3.1%) 13.030s (-4.4%) 1.350s 3 1.00x
▲ Vercel Nitro 11.875s (~) 14.030s (+2.6%) 2.155s 3 1.02x
▲ Vercel Next.js (Turbopack) 12.763s (+0.7%) 14.786s (~) 2.023s 3 1.09x

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

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 13.522s (-1.0%) 14.025s (~) 0.504s 5 1.00x
🐘 Postgres Express 13.630s (~) 14.020s (~) 0.390s 5 1.01x
🐘 Postgres Nitro 13.711s (~) 14.024s (~) 0.312s 5 1.01x
🐘 Postgres Next.js (Turbopack) 13.713s (~) 14.020s (~) 0.306s 5 1.01x
💻 Local Nitro 13.725s (+1.2%) 14.027s (~) 0.302s 5 1.02x
💻 Local Express 13.766s (~) 14.027s (~) 0.261s 5 1.02x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 16.251s (-3.1%) 17.998s (-2.3%) 1.748s 4 1.00x
▲ Vercel Express 16.333s (-0.6%) 17.922s (-4.2%) 1.589s 4 1.01x
▲ Vercel Next.js (Turbopack) 17.301s (+0.6%) 19.205s (-0.5%) 1.904s 4 1.06x

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

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 12.102s (-0.6%) 12.523s (-3.9%) 0.420s 8 1.00x
💻 Local Express 12.147s (~) 13.026s (~) 0.880s 7 1.00x
🐘 Postgres Express 12.164s (-2.6%) 13.019s (~) 0.855s 7 1.01x
🐘 Postgres Next.js (Turbopack) 12.326s (-0.9%) 13.014s (+0.8%) 0.688s 7 1.02x
💻 Local Nitro 12.342s (+1.9%) 13.025s (~) 0.683s 7 1.02x
🐘 Postgres Nitro 12.440s (+2.0%) 13.021s (~) 0.581s 7 1.03x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 17.454s (-0.9%) 19.249s (~) 1.795s 5 1.00x
▲ Vercel Nitro 17.623s (+1.5%) 19.808s (+4.5%) 2.185s 5 1.01x
▲ Vercel Next.js (Turbopack) 20.698s (+4.2%) 22.914s (+4.7%) 2.216s 4 1.19x

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

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.178s (~) 2.008s (~) 0.830s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.194s (-6.2% 🟢) 2.008s (-1.6%) 0.814s 15 1.01x
🐘 Postgres Nitro 1.225s (+1.9%) 2.008s (~) 0.783s 15 1.04x
💻 Local Next.js (Turbopack) 1.345s (-5.5% 🟢) 2.006s (~) 0.661s 15 1.14x
💻 Local Nitro 1.405s (~) 2.007s (~) 0.601s 15 1.19x
💻 Local Express 1.419s (+1.9%) 2.006s (~) 0.587s 15 1.20x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.022s (-7.6% 🟢) 4.001s (+5.3% 🔺) 1.979s 8 1.00x
▲ Vercel Express 2.064s (+4.6%) 3.615s (-3.1%) 1.551s 9 1.02x
▲ Vercel Next.js (Turbopack) 3.062s (-7.6% 🟢) 4.842s (-5.5% 🟢) 1.780s 7 1.51x

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

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.321s (~) 2.315s (-18.1% 🟢) 0.995s 13 1.00x
🐘 Postgres Next.js (Turbopack) 1.333s (~) 3.110s (+25.4% 🔺) 1.778s 10 1.01x
🐘 Postgres Express 1.343s (-0.9%) 2.315s (~) 0.973s 13 1.02x
💻 Local Next.js (Turbopack) 2.131s (-22.2% 🟢) 2.917s (-6.2% 🟢) 0.786s 11 1.61x
💻 Local Nitro 2.387s (-5.3% 🟢) 3.009s (-3.2%) 0.622s 10 1.81x
💻 Local Express 2.693s (+4.3%) 3.209s (+6.7% 🔺) 0.517s 10 2.04x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.303s (-3.7%) 3.911s (+2.2%) 1.608s 8 1.00x
▲ Vercel Express 2.310s (-12.8% 🟢) 3.573s (-11.2% 🟢) 1.263s 9 1.00x
▲ Vercel Next.js (Turbopack) 4.258s (+17.4% 🔺) 5.955s (+3.1%) 1.697s 6 1.85x

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

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.606s (+1.1%) 4.136s (+3.1%) 2.530s 8 1.00x
🐘 Postgres Nitro 1.639s (+3.2%) 4.306s (+7.3% 🔺) 2.666s 7 1.02x
🐘 Postgres Next.js (Turbopack) 2.749s (+51.0% 🔺) 5.515s (+12.8% 🔺) 2.766s 6 1.71x
💻 Local Next.js (Turbopack) 3.681s (-53.0% 🟢) 4.441s (-44.6% 🟢) 0.760s 7 2.29x
💻 Local Express 4.527s (-32.0% 🟢) 5.182s (-30.1% 🟢) 0.654s 6 2.82x
💻 Local Nitro 4.549s (-26.0% 🟢) 4.869s (-28.6% 🟢) 0.320s 7 2.83x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.526s (+31.5% 🔺) 5.213s (+20.2% 🔺) 1.687s 6 1.00x
▲ Vercel Nitro 3.765s (+42.4% 🔺) 5.606s (+32.6% 🔺) 1.842s 6 1.07x
▲ Vercel Next.js (Turbopack) 4.961s (+19.6% 🔺) 6.853s (+12.2% 🔺) 1.892s 5 1.41x

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

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.198s (+1.3%) 2.008s (~) 0.810s 15 1.00x
🐘 Postgres Express 1.202s (+1.9%) 2.008s (~) 0.806s 15 1.00x
🐘 Postgres Nitro 1.216s (+3.7%) 2.007s (~) 0.791s 15 1.01x
💻 Local Next.js (Turbopack) 1.369s (-4.2%) 2.009s (~) 0.640s 15 1.14x
💻 Local Nitro 1.444s (+5.3% 🔺) 2.006s (~) 0.562s 15 1.21x
💻 Local Express 1.468s (+1.5%) 2.007s (~) 0.539s 15 1.22x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.059s (+7.4% 🔺) 3.951s (+11.8% 🔺) 1.892s 8 1.00x
▲ Vercel Express 2.064s (+9.1% 🔺) 3.549s (-4.4%) 1.484s 9 1.00x
▲ Vercel Next.js (Turbopack) 3.505s (+13.9% 🔺) 5.377s (+9.0% 🔺) 1.872s 6 1.70x

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

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.327s (+1.0%) 2.510s (-3.2%) 1.183s 12 1.00x
🐘 Postgres Next.js (Turbopack) 1.337s (-4.8%) 3.010s (+18.9% 🔺) 1.673s 10 1.01x
🐘 Postgres Express 1.349s (+3.2%) 2.393s (-3.2%) 1.044s 13 1.02x
💻 Local Next.js (Turbopack) 2.373s (-11.1% 🟢) 3.009s (-6.3% 🟢) 0.636s 10 1.79x
💻 Local Nitro 2.548s (-6.9% 🟢) 3.009s (-10.0% 🟢) 0.461s 10 1.92x
💻 Local Express 2.827s (+7.2% 🔺) 3.209s (+6.6% 🔺) 0.382s 10 2.13x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.304s (-8.1% 🟢) 3.624s (-8.3% 🟢) 1.320s 9 1.00x
▲ Vercel Nitro 2.433s (+5.0%) 3.969s (+5.1% 🔺) 1.536s 8 1.06x
▲ Vercel Next.js (Turbopack) 3.731s (+9.5% 🔺) 5.467s (+3.7%) 1.737s 6 1.62x

🔍 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 🥇 Express 1.623s (+1.9%) 4.011s (-3.0%) 2.389s 8 1.00x
🐘 Postgres Nitro 1.629s (-1.0%) 4.302s (~) 2.673s 7 1.00x
🐘 Postgres Next.js (Turbopack) 3.106s (+19.1% 🔺) 6.015s (+15.0% 🔺) 2.909s 5 1.91x
💻 Local Express 4.826s (-23.8% 🟢) 6.016s (-11.7% 🟢) 1.191s 5 2.97x
💻 Local Nitro 4.995s (-22.5% 🟢) 6.013s (-18.9% 🟢) 1.018s 5 3.08x
💻 Local Next.js (Turbopack) 5.195s (-18.4% 🟢) 5.846s (-19.0% 🟢) 0.652s 6 3.20x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.880s (+1.5%) 4.326s (-1.4%) 1.446s 7 1.00x
▲ Vercel Express 3.106s (+9.8% 🔺) 4.610s (+1.2%) 1.504s 7 1.08x
▲ Vercel Next.js (Turbopack) 4.563s (+4.2%) 6.695s (+8.4% 🔺) 2.132s 5 1.58x

🔍 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
🐘 Postgres 🥇 Express 0.550s (~) 1.023s (+1.7%) 0.473s 59 1.00x
🐘 Postgres Nitro 0.570s (+1.1%) 1.006s (-1.6%) 0.436s 60 1.04x
💻 Local Next.js (Turbopack) 0.574s (-13.1% 🟢) 1.004s (-5.0% 🟢) 0.430s 60 1.04x
💻 Local Nitro 0.617s (+2.3%) 1.022s (-1.7%) 0.405s 59 1.12x
💻 Local Express 0.620s (+12.3% 🔺) 1.022s (+1.7%) 0.402s 59 1.13x
🐘 Postgres Next.js (Turbopack) 0.633s (+4.2%) 1.059s (+0.7%) 0.427s 57 1.15x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.347s (-12.8% 🟢) 3.699s (-13.8% 🟢) 1.352s 17 1.00x
▲ Vercel Nitro 2.412s (-12.3% 🟢) 4.126s (-7.4% 🟢) 1.713s 15 1.03x
▲ Vercel Next.js (Turbopack) 3.496s (-3.2%) 5.405s (~) 1.909s 12 1.49x

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

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.269s (-6.1% 🟢) 2.029s (~) 0.760s 45 1.00x
🐘 Postgres Nitro 1.394s (+6.1% 🔺) 2.030s (-1.2%) 0.636s 45 1.10x
🐘 Postgres Next.js (Turbopack) 1.400s (-6.0% 🟢) 2.029s (-5.0% 🟢) 0.629s 45 1.10x
💻 Local Next.js (Turbopack) 1.423s (-4.5%) 2.028s (+1.1%) 0.605s 45 1.12x
💻 Local Express 1.522s (+8.7% 🔺) 2.006s (~) 0.484s 45 1.20x
💻 Local Nitro 1.534s (+7.3% 🔺) 2.028s (+1.1%) 0.494s 45 1.21x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 5.730s (-6.6% 🟢) 7.550s (~) 1.821s 12 1.00x
▲ Vercel Express 5.950s (-3.4%) 7.396s (-5.8% 🟢) 1.446s 13 1.04x
▲ Vercel Next.js (Turbopack) 8.401s (+5.9% 🔺) 10.251s (+4.7%) 1.850s 9 1.47x

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

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.506s (-4.7%) 3.033s (-1.7%) 0.528s 40 1.00x
🐘 Postgres Next.js (Turbopack) 2.742s (-7.0% 🟢) 3.034s (-12.1% 🟢) 0.293s 40 1.09x
🐘 Postgres Nitro 2.747s (+5.5% 🔺) 3.034s (~) 0.287s 40 1.10x
💻 Local Next.js (Turbopack) 3.044s (-4.9%) 3.494s (-12.9% 🟢) 0.449s 35 1.21x
💻 Local Nitro 3.250s (+2.3%) 4.009s (+1.6%) 0.759s 30 1.30x
💻 Local Express 3.337s (+11.7% 🔺) 4.042s (+16.6% 🔺) 0.706s 30 1.33x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 11.315s (-3.3%) 12.944s (-3.3%) 1.628s 10 1.00x
▲ Vercel Nitro 11.432s (-3.5%) 13.485s (+0.6%) 2.052s 10 1.01x
▲ Vercel Next.js (Turbopack) 17.615s (+4.5%) 19.338s (+3.4%) 1.723s 7 1.56x

🔍 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.180s (-22.3% 🟢) 1.006s (~) 0.827s 60 1.00x
🐘 Postgres Express 0.215s (-3.1%) 1.006s (~) 0.791s 60 1.20x
🐘 Postgres Nitro 0.228s (+6.3% 🔺) 1.007s (~) 0.778s 60 1.27x
💻 Local Nitro 0.503s (+17.0% 🔺) 1.005s (~) 0.502s 60 2.80x
💻 Local Express 0.552s (+22.8% 🔺) 1.005s (~) 0.453s 60 3.07x
💻 Local Next.js (Turbopack) 0.577s (-8.2% 🟢) 1.021s (+1.6%) 0.444s 59 3.21x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 1.129s (+10.1% 🔺) 2.805s (+15.0% 🔺) 1.677s 22 1.00x
▲ Vercel Express 1.272s (+36.6% 🔺) 2.594s (+4.7%) 1.321s 24 1.13x
▲ Vercel Next.js (Turbopack) 2.397s (+20.8% 🔺) 4.119s (+7.2% 🔺) 1.723s 15 2.12x

🔍 Observability: Nitro | Express | 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.295s (-7.1% 🟢) 1.017s (~) 0.722s 89 1.00x
🐘 Postgres Express 0.323s (-3.0%) 1.017s (+1.1%) 0.694s 89 1.09x
🐘 Postgres Nitro 0.357s (+6.3% 🔺) 1.006s (~) 0.649s 90 1.21x
💻 Local Next.js (Turbopack) 2.377s (-18.8% 🟢) 3.009s (-10.9% 🟢) 0.632s 30 8.05x
💻 Local Nitro 2.429s (+26.2% 🔺) 3.009s (+19.9% 🔺) 0.580s 30 8.22x
💻 Local Express 2.504s (+15.1% 🔺) 3.010s (+8.8% 🔺) 0.506s 30 8.47x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.604s (+12.7% 🔺) 3.013s (~) 1.410s 32 1.00x
▲ Vercel Nitro 1.885s (+16.5% 🔺) 3.515s (+16.9% 🔺) 1.630s 26 1.18x
▲ Vercel Next.js (Turbopack) 2.843s (+14.0% 🔺) 4.602s (+12.0% 🔺) 1.759s 20 1.77x

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

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.507s (-6.7% 🟢) 1.041s (-6.9% 🟢) 0.534s 116 1.00x
🐘 Postgres Next.js (Turbopack) 0.519s (+3.8%) 3.086s (+22.7% 🔺) 2.567s 39 1.02x
🐘 Postgres Nitro 0.563s (+2.5%) 1.128s (~) 0.566s 107 1.11x
💻 Local Next.js (Turbopack) 5.467s (-49.4% 🟢) 8.026s (-31.7% 🟢) 2.559s 15 10.78x
💻 Local Nitro 5.486s (-43.1% 🟢) 8.668s (-19.6% 🟢) 3.182s 14 10.82x
💻 Local Express 5.561s (-39.8% 🟢) 8.812s (-15.6% 🟢) 3.251s 14 10.96x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.017s (+20.3% 🔺) 3.938s (+14.2% 🔺) 1.921s 31 1.00x
▲ Vercel Express 2.407s (+35.4% 🔺) 4.190s (+14.5% 🔺) 1.782s 29 1.19x
▲ Vercel Next.js (Turbopack) 4.434s (+9.1% 🔺) 6.511s (+11.0% 🔺) 2.078s 19 2.20x

🔍 Observability: Nitro | Express | 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 🥇 Next.js (Turbopack) 1.121s (-1.6%) 1.973s (~) 0.008s (-30.8% 🟢) 2.015s (~) 0.893s 10 1.00x
🐘 Postgres Express 1.156s (~) 1.998s (~) 0.001s (-8.3% 🟢) 2.011s (~) 0.855s 10 1.03x
💻 Local Express 1.160s (+1.8%) 2.004s (~) 0.010s (-4.7%) 2.018s (~) 0.857s 10 1.03x
💻 Local Nitro 1.163s (+0.5%) 2.005s (~) 0.012s (+13.1% 🔺) 2.019s (~) 0.857s 10 1.04x
🐘 Postgres Next.js (Turbopack) 1.172s (-4.0%) 2.000s (+0.6%) 0.001s (+44.4% 🔺) 2.011s (~) 0.838s 10 1.05x
🐘 Postgres Nitro 1.185s (~) 2.002s (~) 0.001s (~) 2.010s (~) 0.826s 10 1.06x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.014s (+5.4% 🔺) 8.633s (+177.5% 🔺) 0.405s (-75.3% 🟢) 9.566s (+85.1% 🔺) 7.552s 10 1.00x
▲ Vercel Express 2.036s (~) 8.427s (+151.3% 🔺) 0.344s (-75.2% 🟢) 9.257s (+76.8% 🔺) 7.221s 10 1.01x
▲ Vercel Next.js (Turbopack) 3.482s (+8.5% 🔺) 8.740s (+118.7% 🔺) 0.260s (-68.6% 🟢) 10.171s (+66.4% 🔺) 6.688s 10 1.73x

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

stream pipeline with 5 transform steps (1MB)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 1.512s (-4.2%) 1.976s (~) 0.011s (-3.7%) 2.023s (~) 0.510s 30 1.00x
🐘 Postgres Express 1.538s (-3.1%) 1.998s (-1.9%) 0.005s (+4.6%) 2.025s (-1.7%) 0.487s 30 1.02x
💻 Local Express 1.577s (+2.4%) 2.009s (~) 0.014s (+6.7% 🔺) 2.027s (~) 0.450s 30 1.04x
💻 Local Nitro 1.601s (+2.7%) 2.010s (~) 0.013s (+2.0%) 2.026s (~) 0.425s 30 1.06x
🐘 Postgres Next.js (Turbopack) 1.628s (-13.9% 🟢) 2.009s (-11.3% 🟢) 0.005s (-36.0% 🟢) 2.026s (-12.0% 🟢) 0.398s 30 1.08x
🐘 Postgres Nitro 1.673s (+6.4% 🔺) 2.039s (+1.6%) 0.005s (-6.7% 🟢) 2.059s (+1.5%) 0.386s 30 1.11x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 5.489s (-2.7%) 7.180s (~) 0.131s (-35.9% 🟢) 7.806s (-1.5%) 2.316s 8 1.00x
▲ Vercel Nitro 5.577s (-1.6%) 7.528s (+8.1% 🔺) 0.220s (-22.5% 🟢) 8.277s (+7.9% 🔺) 2.700s 8 1.02x
▲ Vercel Next.js (Turbopack) 10.361s (+9.9% 🔺) 12.134s (+12.8% 🔺) 0.182s (-29.1% 🟢) 13.114s (+10.9% 🔺) 2.753s 5 1.89x

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

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.759s (-2.5%) 1.046s (-1.3%) 0.000s (+Infinity% 🔺) 1.061s (-1.7%) 0.302s 57 1.00x
🐘 Postgres Nitro 0.848s (+10.0% 🔺) 1.147s (+3.8%) 0.000s (+3.8%) 1.162s (+3.9%) 0.314s 52 1.12x
🐘 Postgres Next.js (Turbopack) 1.042s (-24.3% 🟢) 1.393s (-29.0% 🟢) 0.000s (NaN%) 1.402s (-30.0% 🟢) 0.361s 43 1.37x
💻 Local Next.js (Turbopack) 1.173s (-15.1% 🟢) 1.889s (-4.6%) 0.000s (+3.1%) 1.920s (-4.8%) 0.747s 32 1.55x
💻 Local Nitro 1.323s (+1.9%) 1.889s (-6.2% 🟢) 0.000s (+74.1% 🔺) 1.891s (-6.2% 🟢) 0.568s 32 1.74x
💻 Local Express 1.381s (+8.4% 🔺) 2.013s (~) 0.000s (-66.7% 🟢) 2.016s (~) 0.635s 30 1.82x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.012s (+4.6%) 4.570s (+5.5% 🔺) 0.000s (NaN%) 5.042s (+4.6%) 2.030s 12 1.00x
▲ Vercel Nitro 3.038s (-98.4% 🟢) 4.977s (-97.3% 🟢) 0.000s (NaN%) 5.593s (-97.0% 🟢) 2.555s 11 1.01x
▲ Vercel Next.js (Turbopack) 4.720s (+11.4% 🔺) 5.779s (+6.4% 🔺) 0.000s (NaN%) 6.975s (+12.5% 🔺) 2.255s 9 1.57x

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

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.727s (~) 2.301s (+0.6%) 0.000s (+107.7% 🔺) 2.316s (~) 0.589s 26 1.00x
🐘 Postgres Nitro 1.878s (-0.7%) 2.435s (~) 0.000s (+100.0% 🔺) 2.451s (~) 0.572s 25 1.09x
🐘 Postgres Next.js (Turbopack) 2.515s (-11.1% 🟢) 3.052s (-9.1% 🟢) 0.000s (NaN%) 3.060s (-9.8% 🟢) 0.545s 20 1.46x
💻 Local Next.js (Turbopack) 2.984s (-14.4% 🟢) 3.643s (-8.7% 🟢) 0.000s (-70.6% 🟢) 3.675s (-8.9% 🟢) 0.691s 17 1.73x
💻 Local Nitro 3.276s (-11.1% 🟢) 3.840s (-11.0% 🟢) 0.000s (-41.7% 🟢) 3.843s (-11.0% 🟢) 0.567s 16 1.90x
💻 Local Express 3.440s (+1.3%) 3.964s (-1.5%) 0.001s (-25.0% 🟢) 3.968s (-1.5%) 0.527s 16 1.99x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 4.629s (+6.5% 🔺) 6.466s (+9.8% 🔺) 0.000s (NaN%) 6.974s (+8.0% 🔺) 2.345s 9 1.00x
▲ Vercel Express 4.712s (+9.1% 🔺) 6.087s (+7.1% 🔺) 0.000s (NaN%) 6.563s (+6.8% 🔺) 1.852s 10 1.02x
▲ Vercel Next.js (Turbopack) 7.572s (+9.1% 🔺) 8.792s (+10.9% 🔺) 0.000s (NaN%) 10.246s (+15.9% 🔺) 2.674s 6 1.64x

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

Summary

Fastest Framework by World

Winner determined by most benchmark wins

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

Winner determined by most benchmark wins

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

@github-actions

github-actions Bot commented Jun 3, 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 1605 0 219 1824
✅ 📦 Local Production 1605 0 219 1824
✅ 🐘 Local Postgres 1593 0 231 1824
✅ 🪟 Windows 152 0 0 152
✅ 📋 Other 885 0 179 1064
Total 7282 0 1078 8360

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 152 0 0
✅ nextjs-webpack-canary 133 0 19
✅ nextjs-webpack-stable 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 152 0 0
✅ nextjs-webpack-canary 133 0 19
✅ nextjs-webpack-stable 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 151 0 1
✅ nextjs-webpack-canary 132 0 20
✅ nextjs-webpack-stable 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

@karthikscale3 karthikscale3 changed the title [codex] Add workflow analytics world APIs Add workflow analytics world APIs Jun 3, 2026
@karthikscale3 karthikscale3 force-pushed the codex/workflow-analytics-apis branch from 066d69c to b733f17 Compare June 25, 2026 21:45
workflowEncryptionEnabled: NullableBooleanSchema,
});

export const AnalyticsEventSchema = z.object({

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.

This duplicates a lot of schemas from the world otherwise, when I'd expect we want the analytics schemas to be keeping parity with the regular storage schemas. So maybe I'd define those as the storage schema +- some attributes, instead of copying entirely

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I considered deriving these from the storage schemas, but I think keeping analytics schemas standalone is the safer contract here.

The analytics namespace is intentionally a metadata-only read model, not a storage object with fields removed. Several shapes diverge from runtime storage: events are flattened instead of nested under eventData, hook rows omit secret/runtime ownership fields, and the read model carries fields like workflowCoreVersion, workflowEncryptionEnabled, region, vercelId, and requestId.

I’m also wary of deriving via omit, because the failure mode for future storage fields is bad: payload/secret fields could become accepted by analytics unless we remember to exclude them. With standalone schemas, every analytics field is explicitly opted in and reviewable.

I did reuse the shared enum schemas where parity matters (WorkflowRunStatusSchema, StepStatusSchema, EventTypeSchema, WaitStatusSchema). Happy to add a short comment documenting that these schemas are intentionally standalone metadata-only read contracts, if that would help make the boundary clearer.

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

Approve — clean, well-isolated metadata-only read namespace

Solid foundation for the analytics surface. The design choices are right where it matters:

  • analytics?: Analytics is optional on World — backends without a metadata read path leave it unset and consumers fall back to runtime storage APIs. Clean capability detection, no breaking change for local/postgres.
  • Genuinely metadata-only. I grepped the entire analytics layer (schema + vercel impl): zero token references and no payload-bearing fields (input/output/result/error/payload). Hooks carry status/timestamps/flags but no token, runs/steps/events/waits carry ids/statuses/timestamps/names/error codes only. This is exactly the separation you want — the secret and payloads structurally cannot leak through this surface.
  • Injection-safe client. Every path parameter goes through encodeURIComponent; the only un-encoded interpolations are list endpoints with no path params (query strings built via URLSearchParams). Every response is Zod-validated against the analytics schema.
  • createVercelWorld wiring is correct (analytics: createAnalytics(config)), the new schemas are exported from @workflow/world, and the changeset (minor for world + world-vercel) is right.

Built both packages; tsc --noEmit clean on @workflow/world and @workflow/world-vercel.

On @VaguelySerious's schema-duplication point

It's a fair maintainability concern, but I'd lean toward keeping these as standalone schemas rather than deriving them from the storage schemas (StorageSchema.omit(...)), for two reasons:

  1. They're not a strict subset. The analytics rows add fields the storage schemas don't have (region, vercelId, requestId, runCreatedAt on events; the flattened top-level shape generally), and omit many. A derivation would be omit(...).extend(...) with enough divergence that it wouldn't actually reduce surface area much.
  2. Coupling has a security downside here. The whole point of this namespace is that payload/secret fields can never appear in it. If analytics derived from the storage schema via omit, a future field added to the storage schema would land in analytics by default unless someone remembers to omit it — the failure mode is "secret leaks into the metadata surface," which is exactly what we don't want to make the default. Independent schemas make adding an analytics field an explicit, reviewable act.

That said, a middle ground worth considering (non-blocking): a couple of shared enum/primitive building blocks (the status enums are already imported from the storage modules — good) and a comment on each analytics schema noting it intentionally mirrors a subset of the storage shape, so the parity expectation is documented even though the schemas stay separate. I'd ship as-is.

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

LGTM, I understand the reasoning behind the zod duplication. Maybe we should add a note in the agents file to ensure we don't accidentally cause drift here, but not required

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Backport PR opened against stable: #2734. Merge conflicts were resolved by AI — please review carefully. (backport job run)

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.

4 participants