Skip to content

feat: allow start() to be called directly inside workflow functions#1491

Open
pranaygp wants to merge 6 commits intomainfrom
pgp/revert-revert-start
Open

feat: allow start() to be called directly inside workflow functions#1491
pranaygp wants to merge 6 commits intomainfrom
pgp/revert-revert-start

Conversation

@pranaygp
Copy link
Copy Markdown
Collaborator

@pranaygp pranaygp commented Mar 23, 2026

Summary

Add "use step" to start() so it can be called directly from "use workflow" functions, without needing a wrapper step function.

This is a dramatically simplified replacement for the original PR approach. Instead of complex VM-side proxy classes and builtin step delegation, the entire implementation is:

  1. Add "use step" to start() in packages/core/src/runtime/start.ts
  2. Re-export start from @workflow/core/runtime/start in api-workflow.ts (instead of a throwing stub)

This works because:

Changes

  • packages/core/src/runtime/start.ts: Add "use step" directive
  • packages/workflow/src/api-workflow.ts: Re-export start from core instead of stub
  • workbench/example/workflows/99_e2e.ts: Add startFromWorkflow and fibonacciWorkflow e2e workflows
  • packages/core/e2e/e2e.test.ts: Add e2e tests
  • workbench/nextjs-turbopack/app/workflows/definitions.ts: Add default args

E2E Tests

  • startFromWorkflow: Parent spawns child via start(), child signals parent via hook, verifies bidirectional communication
  • fibonacciWorkflow: Recursive workflow composition — fib(6) = 8 via tree of child workflows using Promise.all([start(...), start(...)])

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 23, 2026

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 Apr 10, 2026 8:49am
example-nextjs-workflow-webpack Ready Ready Preview, Comment Apr 10, 2026 8:49am
example-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-astro-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-express-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-fastify-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-hono-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-nitro-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-nuxt-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-sveltekit-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workbench-vite-workflow Ready Ready Preview, Comment Apr 10, 2026 8:49am
workflow-docs Ready Ready Preview, Comment, Open in v0 Apr 10, 2026 8:49am
workflow-swc-playground Ready Ready Preview, Comment Apr 10, 2026 8:49am

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 23, 2026

🦋 Changeset detected

Latest commit: e75a208

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

This PR includes changesets to release 16 packages
Name Type
@workflow/core Minor
workflow Minor
@workflow/builders Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/world-testing Patch
@workflow/ai Major
@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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 23, 2026

📊 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 🥇 Express 0.037s (-14.0% 🟢) 1.005s (~) 0.968s 10 1.00x
💻 Local Nitro 0.047s (+26.4% 🔺) 1.005s (~) 0.958s 10 1.27x
💻 Local Next.js (Turbopack) 0.047s 1.005s 0.958s 10 1.29x
🐘 Postgres Next.js (Turbopack) 0.056s 1.012s 0.956s 10 1.52x
🐘 Postgres Nitro 0.059s (-5.7% 🟢) 1.011s (~) 0.952s 10 1.61x
🐘 Postgres Express 0.064s (-3.9%) 1.016s (+0.7%) 0.952s 10 1.73x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 0.209s (-13.6% 🟢) 1.974s (-7.1% 🟢) 1.765s 10 1.00x
▲ Vercel Nitro 0.216s (-23.6% 🟢) 2.067s (-16.7% 🟢) 1.851s 10 1.03x
▲ Vercel Next.js (Turbopack) 0.308s (-30.8% 🟢) 2.210s (-0.6%) 1.902s 10 1.47x

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

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 1.101s (-2.7%) 2.005s (~) 0.905s 10 1.00x
💻 Local Next.js (Turbopack) 1.109s 2.006s 0.897s 10 1.01x
💻 Local Nitro 1.137s (+3.1%) 2.006s (~) 0.869s 10 1.03x
🐘 Postgres Next.js (Turbopack) 1.138s 2.010s 0.872s 10 1.03x
🐘 Postgres Express 1.149s (~) 2.011s (~) 0.862s 10 1.04x
🐘 Postgres Nitro 1.150s (~) 2.010s (~) 0.860s 10 1.04x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 1.857s (-11.4% 🟢) 3.998s (+4.2%) 2.141s 10 1.00x
▲ Vercel Next.js (Turbopack) 1.870s (-9.7% 🟢) 3.538s (-4.2%) 1.668s 10 1.01x
▲ Vercel Express 1.897s (+1.4%) 4.054s (+5.5% 🔺) 2.158s 10 1.02x

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

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 10.633s (-2.8%) 11.023s (~) 0.390s 3 1.00x
💻 Local Next.js (Turbopack) 10.768s 11.023s 0.254s 3 1.01x
🐘 Postgres Nitro 10.863s (~) 11.023s (~) 0.160s 3 1.02x
🐘 Postgres Next.js (Turbopack) 10.864s 11.022s 0.158s 3 1.02x
🐘 Postgres Express 10.908s (~) 11.022s (~) 0.114s 3 1.03x
💻 Local Nitro 10.959s (+2.7%) 11.024s (~) 0.065s 3 1.03x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 16.692s (-0.8%) 18.825s (-0.8%) 2.134s 2 1.00x
▲ Vercel Next.js (Turbopack) 16.747s (-5.7% 🟢) 18.948s (~) 2.201s 2 1.00x
▲ Vercel Express 17.608s (+5.2% 🔺) 19.207s (+2.6%) 1.598s 2 1.05x

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

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 14.213s (-5.6% 🟢) 15.030s (-6.2% 🟢) 0.816s 4 1.00x
🐘 Postgres Nitro 14.506s (~) 15.023s (~) 0.517s 4 1.02x
🐘 Postgres Next.js (Turbopack) 14.509s 15.024s 0.515s 4 1.02x
🐘 Postgres Express 14.544s (~) 15.021s (~) 0.477s 4 1.02x
💻 Local Next.js (Turbopack) 14.590s 15.028s 0.438s 4 1.03x
💻 Local Nitro 15.079s (+6.0% 🔺) 15.783s (+5.0% 🔺) 0.704s 4 1.06x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 29.813s (-5.1% 🟢) 32.027s (-4.8%) 2.214s 2 1.00x
▲ Vercel Express 30.896s (+2.5%) 33.537s (+4.0%) 2.641s 2 1.04x
▲ Vercel Next.js (Turbopack) 32.616s (-3.9%) 34.375s (-4.4%) 1.759s 2 1.09x

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

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 13.905s 14.165s 0.260s 7 1.00x
🐘 Postgres Express 14.023s (~) 14.592s (-1.0%) 0.568s 7 1.01x
🐘 Postgres Nitro 14.415s (+3.9%) 15.191s (+8.4% 🔺) 0.776s 6 1.04x
💻 Local Express 15.005s (-11.4% 🟢) 15.530s (-8.8% 🟢) 0.525s 6 1.08x
💻 Local Next.js (Turbopack) 15.974s 16.195s 0.220s 6 1.15x
💻 Local Nitro 16.747s (+12.2% 🔺) 17.031s (+13.3% 🔺) 0.284s 6 1.20x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 50.249s (-6.8% 🟢) 52.761s (-5.7% 🟢) 2.512s 2 1.00x
▲ Vercel Next.js (Turbopack) 51.048s (-6.7% 🟢) 52.396s (-8.1% 🟢) 1.348s 2 1.02x
▲ Vercel Express 53.337s (+1.5%) 55.253s (+0.9%) 1.916s 2 1.06x

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

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.252s 2.010s 0.757s 15 1.00x
🐘 Postgres Express 1.270s (~) 2.010s (~) 0.740s 15 1.01x
🐘 Postgres Nitro 1.282s (+1.2%) 2.009s (~) 0.727s 15 1.02x
💻 Local Express 1.460s (-4.5%) 2.006s (~) 0.546s 15 1.17x
💻 Local Next.js (Turbopack) 1.500s 2.005s 0.505s 15 1.20x
💻 Local Nitro 1.504s (+0.6%) 2.005s (~) 0.501s 15 1.20x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.264s (-9.3% 🟢) 4.224s (+7.2% 🔺) 1.961s 8 1.00x
▲ Vercel Next.js (Turbopack) 2.377s (~) 3.725s (-3.7%) 1.349s 9 1.05x
▲ Vercel Express 2.585s (+8.9% 🔺) 4.319s (+4.5%) 1.734s 7 1.14x

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

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 2.350s (~) 3.010s (~) 0.660s 10 1.00x
🐘 Postgres Express 2.365s (+1.5%) 3.010s (~) 0.645s 10 1.01x
🐘 Postgres Next.js (Turbopack) 2.426s 3.010s 0.584s 10 1.03x
💻 Local Express 2.557s (-19.7% 🟢) 3.008s (-25.0% 🟢) 0.450s 10 1.09x
💻 Local Next.js (Turbopack) 2.926s 3.208s 0.281s 10 1.25x
💻 Local Nitro 3.022s (+10.8% 🔺) 3.759s (+17.2% 🔺) 0.738s 8 1.29x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.738s (+3.4%) 5.072s (+23.7% 🔺) 2.335s 7 1.00x
▲ Vercel Nitro 2.781s (-9.4% 🟢) 4.435s (-1.5%) 1.654s 7 1.02x
▲ Vercel Next.js (Turbopack) 2.845s (-5.9% 🟢) 4.314s (-2.1%) 1.469s 7 1.04x

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

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 3.467s (-1.0%) 4.012s (~) 0.544s 8 1.00x
🐘 Postgres Express 3.476s (-0.8%) 4.011s (~) 0.535s 8 1.00x
🐘 Postgres Next.js (Turbopack) 3.655s 4.011s 0.356s 8 1.05x
💻 Local Express 6.685s (-19.9% 🟢) 7.017s (-22.2% 🟢) 0.333s 5 1.93x
💻 Local Next.js (Turbopack) 7.381s 7.766s 0.386s 4 2.13x
💻 Local Nitro 8.193s (+5.8% 🔺) 8.772s (+3.0%) 0.579s 4 2.36x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.727s (-7.5% 🟢) 4.847s (+2.8%) 2.120s 7 1.00x
▲ Vercel Next.js (Turbopack) 3.053s (+0.5%) 4.556s (-1.1%) 1.503s 7 1.12x
▲ Vercel Nitro 3.236s (+7.7% 🔺) 4.997s (+7.0% 🔺) 1.761s 7 1.19x

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

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.228s 2.009s 0.782s 15 1.00x
🐘 Postgres Nitro 1.262s (~) 2.009s (~) 0.746s 15 1.03x
🐘 Postgres Express 1.286s (-0.8%) 2.008s (~) 0.722s 15 1.05x
💻 Local Next.js (Turbopack) 1.487s 2.006s 0.519s 15 1.21x
💻 Local Express 1.489s (-4.8%) 2.006s (~) 0.517s 15 1.21x
💻 Local Nitro 1.552s (+3.1%) 2.006s (~) 0.455s 15 1.26x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 1.899s (-2.8%) 4.189s (+9.9% 🔺) 2.290s 8 1.00x
▲ Vercel Express 2.229s (+15.8% 🔺) 4.183s (+12.6% 🔺) 1.954s 8 1.17x
▲ Vercel Next.js (Turbopack) 2.486s (+14.7% 🔺) 3.876s (+8.2% 🔺) 1.390s 8 1.31x

🔍 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 2.377s (+1.8%) 3.011s (~) 0.634s 10 1.00x
🐘 Postgres Next.js (Turbopack) 2.381s 3.008s 0.627s 10 1.00x
🐘 Postgres Express 2.400s (+0.9%) 3.012s (~) 0.612s 10 1.01x
💻 Local Express 2.708s (-14.6% 🟢) 3.007s (-22.6% 🟢) 0.300s 10 1.14x
💻 Local Next.js (Turbopack) 2.797s 3.208s 0.412s 10 1.18x
💻 Local Nitro 2.918s (-16.6% 🟢) 3.453s (-13.9% 🟢) 0.535s 9 1.23x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.381s (-9.1% 🟢) 4.362s (-1.2%) 1.981s 7 1.00x
▲ Vercel Next.js (Turbopack) 2.443s (-1.5%) 4.120s (+6.5% 🔺) 1.676s 8 1.03x
▲ Vercel Nitro 2.484s (-5.2% 🟢) 4.422s (+3.6%) 1.939s 7 1.04x

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

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 3.480s (~) 4.011s (~) 0.531s 8 1.00x
🐘 Postgres Express 3.503s (~) 4.011s (~) 0.508s 8 1.01x
🐘 Postgres Next.js (Turbopack) 3.643s 4.011s 0.368s 8 1.05x
💻 Local Express 7.402s (-27.6% 🟢) 8.017s (-27.3% 🟢) 0.615s 4 2.13x
💻 Local Next.js (Turbopack) 8.136s 8.770s 0.635s 4 2.34x
💻 Local Nitro 8.301s (-2.4%) 9.024s (~) 0.723s 4 2.39x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.507s (+19.6% 🔺) 5.211s (+23.7% 🔺) 1.704s 6 1.00x
▲ Vercel Nitro 3.555s (+37.2% 🔺) 5.676s (+32.2% 🔺) 2.121s 6 1.01x
▲ Vercel Next.js (Turbopack) 3.624s (+4.6%) 5.364s (+11.3% 🔺) 1.740s 6 1.03x

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

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 0.691s (-31.9% 🟢) 1.004s (-40.9% 🟢) 0.313s 60 1.00x
🐘 Postgres Next.js (Turbopack) 0.775s 1.006s 0.231s 60 1.12x
🐘 Postgres Nitro 0.826s (-1.2%) 1.023s (~) 0.197s 59 1.20x
💻 Local Next.js (Turbopack) 0.837s 1.021s 0.184s 59 1.21x
🐘 Postgres Express 0.861s (~) 1.007s (~) 0.146s 60 1.25x
💻 Local Nitro 0.987s (+33.9% 🔺) 1.158s (+15.3% 🔺) 0.172s 52 1.43x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 8.854s (-0.9%) 10.445s (-2.0%) 1.591s 6 1.00x
▲ Vercel Nitro 9.289s (+8.4% 🔺) 11.062s (+8.3% 🔺) 1.774s 6 1.05x
▲ Vercel Express 10.029s (+9.1% 🔺) 12.115s (+10.3% 🔺) 2.086s 6 1.13x

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

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 1.903s 2.100s 0.197s 43 1.00x
🐘 Postgres Nitro 1.946s (~) 2.150s (+2.3%) 0.204s 42 1.02x
🐘 Postgres Express 2.075s (-3.8%) 2.822s (-5.2% 🟢) 0.747s 32 1.09x
💻 Local Express 2.279s (-26.3% 🟢) 3.008s (-25.0% 🟢) 0.729s 30 1.20x
💻 Local Next.js (Turbopack) 2.639s 3.007s 0.368s 30 1.39x
💻 Local Nitro 3.028s (+17.9% 🔺) 3.547s (+11.5% 🔺) 0.520s 26 1.59x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 26.969s (-8.3% 🟢) 28.542s (-9.4% 🟢) 1.573s 4 1.00x
▲ Vercel Next.js (Turbopack) 28.766s (~) 30.076s (-0.9%) 1.310s 3 1.07x
▲ Vercel Express 30.886s (+10.4% 🔺) 33.250s (+11.1% 🔺) 2.364s 3 1.15x

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

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 3.800s 4.043s 0.243s 30 1.00x
🐘 Postgres Nitro 3.925s (-1.6%) 4.217s (-1.9%) 0.291s 29 1.03x
🐘 Postgres Express 3.946s (-8.5% 🟢) 4.367s (-12.9% 🟢) 0.421s 28 1.04x
💻 Local Express 7.404s (-19.6% 🟢) 8.015s (-20.0% 🟢) 0.612s 15 1.95x
💻 Local Next.js (Turbopack) 8.484s 9.017s 0.533s 14 2.23x
💻 Local Nitro 9.222s (+19.6% 🔺) 9.865s (+20.1% 🔺) 0.643s 13 2.43x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 73.672s (+2.8%) 76.839s (+3.3%) 3.166s 2 1.00x
▲ Vercel Next.js (Turbopack) 74.611s (-3.0%) 77.031s (-2.2%) 2.420s 2 1.01x
▲ Vercel Express 77.341s (-1.4%) 79.290s (-1.2%) 1.950s 2 1.05x

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

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.252s 1.007s 0.755s 60 1.00x
🐘 Postgres Nitro 0.283s (~) 1.007s (~) 0.724s 60 1.13x
🐘 Postgres Express 0.285s (-3.7%) 1.006s (~) 0.722s 60 1.13x
💻 Local Next.js (Turbopack) 0.542s 1.004s 0.463s 60 2.15x
💻 Local Express 0.575s (-3.7%) 1.004s (-1.7%) 0.430s 60 2.28x
💻 Local Nitro 0.587s (-11.5% 🟢) 1.005s (~) 0.418s 60 2.33x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 1.529s (-44.0% 🟢) 3.421s (-23.1% 🟢) 1.892s 18 1.00x
▲ Vercel Express 1.553s (+2.0%) 3.317s (+7.1% 🔺) 1.764s 19 1.02x
▲ Vercel Next.js (Turbopack) 1.811s (+25.0% 🔺) 3.365s (+11.8% 🔺) 1.554s 19 1.18x

🔍 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 🥇 Express 0.497s (-5.5% 🟢) 1.007s (~) 0.510s 90 1.00x
🐘 Postgres Next.js (Turbopack) 0.498s 1.007s 0.508s 90 1.00x
🐘 Postgres Nitro 0.520s (+6.5% 🔺) 1.018s (+1.2%) 0.498s 89 1.05x
💻 Local Express 2.419s (-3.7%) 3.007s (~) 0.589s 30 4.87x
💻 Local Next.js (Turbopack) 2.522s 3.009s 0.486s 30 5.08x
💻 Local Nitro 2.658s (-3.2%) 3.009s (-5.5% 🟢) 0.351s 30 5.35x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.361s (-4.5%) 4.252s (+2.7%) 1.890s 22 1.00x
▲ Vercel Express 2.480s (-9.4% 🟢) 4.599s (+5.8% 🔺) 2.119s 20 1.05x
▲ Vercel Next.js (Turbopack) 3.304s (-1.8%) 4.965s (+2.8%) 1.661s 19 1.40x

🔍 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.795s 1.007s 0.212s 120 1.00x
🐘 Postgres Nitro 0.800s (+1.7%) 1.008s (~) 0.209s 120 1.01x
🐘 Postgres Express 0.801s (-4.7%) 1.008s (-1.0%) 0.208s 120 1.01x
💻 Local Express 10.334s (-6.1% 🟢) 10.933s (-6.3% 🟢) 0.599s 11 13.00x
💻 Local Next.js (Turbopack) 10.422s 11.026s 0.604s 11 13.11x
💻 Local Nitro 11.466s (+2.9%) 12.032s (+1.6%) 0.566s 10 14.42x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 5.889s (-23.3% 🟢) 7.878s (-15.8% 🟢) 1.989s 16 1.00x
▲ Vercel Next.js (Turbopack) 6.220s (-14.1% 🟢) 7.701s (-10.6% 🟢) 1.480s 16 1.06x
▲ Vercel Express 6.349s (-7.3% 🟢) 8.125s (-6.6% 🟢) 1.776s 16 1.08x

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

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Express 0.141s (-32.4% 🟢) 1.004s (~) 0.010s (-17.1% 🟢) 1.016s (~) 0.875s 10 1.00x
💻 Local Next.js (Turbopack) 0.173s 1.003s 0.012s 1.018s 0.844s 10 1.23x
🐘 Postgres Next.js (Turbopack) 0.199s 1.000s 0.001s 1.010s 0.812s 10 1.40x
💻 Local Nitro 0.205s (+38.9% 🔺) 1.004s (~) 0.012s (+31.9% 🔺) 1.018s (~) 0.813s 10 1.45x
🐘 Postgres Nitro 0.218s (+9.5% 🔺) 1.000s (~) 0.001s (-18.8% 🟢) 1.010s (~) 0.792s 10 1.54x
🐘 Postgres Express 0.231s (+7.5% 🔺) 0.996s (~) 0.002s (~) 1.010s (~) 0.779s 10 1.63x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.397s (-5.5% 🟢) 2.542s (-16.0% 🟢) 0.745s (+145.7% 🔺) 3.779s (~) 2.382s 10 1.00x
▲ Vercel Nitro 1.435s (-7.7% 🟢) 2.691s (-10.1% 🟢) 0.518s (-11.5% 🟢) 3.675s (-8.3% 🟢) 2.240s 10 1.03x
▲ Vercel Next.js (Turbopack) 1.489s (-8.8% 🟢) 2.833s (-4.7%) 0.476s (+10.6% 🔺) 3.681s (-2.8%) 2.192s 10 1.07x

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

stream pipeline with 5 transform steps (1MB)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.615s (+1.7%) 1.006s (~) 0.004s (+2.1%) 1.022s (~) 0.407s 59 1.00x
🐘 Postgres Next.js (Turbopack) 0.624s 1.009s 0.005s 1.024s 0.400s 59 1.01x
🐘 Postgres Express 0.633s (-2.2%) 1.006s (~) 0.004s (-22.6% 🟢) 1.024s (~) 0.391s 59 1.03x
💻 Local Express 0.667s (-9.3% 🟢) 1.012s (~) 0.009s (-9.9% 🟢) 1.116s (+9.0% 🔺) 0.449s 54 1.08x
💻 Local Nitro 0.845s (+27.7% 🔺) 1.012s (~) 0.010s (-7.7% 🟢) 1.116s (+8.8% 🔺) 0.271s 54 1.37x
💻 Local Next.js (Turbopack) 0.849s 1.010s 0.010s 1.227s 0.378s 49 1.38x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 4.400s (+4.1%) 6.192s (+5.8% 🔺) 0.319s (+44.9% 🔺) 7.003s (+7.9% 🔺) 2.603s 9 1.00x
▲ Vercel Next.js (Turbopack) 4.455s (+8.4% 🔺) 5.673s (+1.6%) 0.272s (-62.5% 🟢) 6.325s (-5.3% 🟢) 1.871s 10 1.01x
▲ Vercel Nitro 5.524s (+26.1% 🔺) 6.965s (+16.2% 🔺) 0.277s (-6.2% 🟢) 7.761s (+13.8% 🔺) 2.237s 8 1.26x

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

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.939s (-0.6%) 1.197s (+4.4%) 0.000s (+4.0%) 1.208s (+4.0%) 0.269s 50 1.00x
🐘 Postgres Next.js (Turbopack) 0.952s 1.246s 0.000s 1.262s 0.310s 49 1.01x
🐘 Postgres Express 0.968s (-2.4%) 1.360s (+1.9%) 0.000s (-100.0% 🟢) 1.372s (~) 0.404s 44 1.03x
💻 Local Express 1.159s (-9.1% 🟢) 2.018s (~) 0.000s (+9.1% 🔺) 2.020s (~) 0.861s 30 1.23x
💻 Local Next.js (Turbopack) 1.237s 2.019s 0.000s 2.022s 0.786s 30 1.32x
💻 Local Nitro 1.283s (-3.2%) 2.021s (~) 0.000s (-47.1% 🟢) 2.023s (~) 0.740s 30 1.37x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.642s (+3.8%) 3.930s (+9.6% 🔺) 0.000s (-100.0% 🟢) 4.435s (+8.1% 🔺) 1.793s 14 1.00x
▲ Vercel Express 3.060s (+15.8% 🔺) 4.519s (+21.7% 🔺) 0.000s (+15.4% 🔺) 5.000s (+20.7% 🔺) 1.939s 13 1.16x
▲ Vercel Next.js (Turbopack) 3.253s (~) 4.420s (+0.8%) 0.001s (+433.3% 🔺) 4.788s (~) 1.535s 13 1.23x

🔍 Observability: Nitro | Express | 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 🥇 Nitro 1.791s (~) 2.213s (+5.5% 🔺) 0.000s (-100.0% 🟢) 2.231s (+5.6% 🔺) 0.440s 28 1.00x
🐘 Postgres Next.js (Turbopack) 1.859s 2.145s 0.000s 2.152s 0.293s 28 1.04x
🐘 Postgres Express 1.879s (+5.2% 🔺) 2.219s (+3.6%) 0.000s (+Infinity% 🔺) 2.236s (+3.9%) 0.357s 27 1.05x
💻 Local Express 3.381s (-7.7% 🟢) 4.033s (-3.3%) 0.000s (-81.8% 🟢) 4.035s (-3.3%) 0.654s 15 1.89x
💻 Local Next.js (Turbopack) 3.542s 4.096s 0.000s 4.102s 0.559s 15 1.98x
💻 Local Nitro 3.694s (-6.4% 🟢) 4.099s (-9.6% 🟢) 0.000s (-66.1% 🟢) 4.102s (-9.6% 🟢) 0.408s 15 2.06x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.414s (+0.6%) 5.020s (+3.4%) 0.000s (-33.3% 🟢) 5.471s (+3.0%) 2.057s 12 1.00x
▲ Vercel Next.js (Turbopack) 4.227s (-2.8%) 5.264s (-5.6% 🟢) 0.000s (-100.0% 🟢) 5.668s (-5.2% 🟢) 1.442s 11 1.24x
▲ Vercel Nitro 4.589s (+29.1% 🔺) 6.124s (+25.2% 🔺) 0.001s (+300.0% 🔺) 6.598s (+23.9% 🔺) 2.009s 10 1.34x

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

Summary

Fastest Framework by World

Winner determined by most benchmark wins

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

Winner determined by most benchmark wins

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

Worlds:

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

📋 View full workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 23, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
❌ ▲ Vercel Production 944 1 67 1012
✅ 💻 Local Development 766 0 154 920
❌ 📦 Local Production 921 1 182 1104
❌ 🐘 Local Postgres 919 3 182 1104
✅ 🪟 Windows 84 0 8 92
❌ 🌍 Community Worlds 137 76 24 237
✅ 📋 Other 234 0 42 276
Total 4005 81 659 4745

❌ Failed Tests

▲ Vercel Production (1 failed)

nextjs-turbopack (1 failed):

  • error handling error propagation step errors basic step error preserves message and stack trace
📦 Local Production (1 failed)

nextjs-turbopack-stable (1 failed):

  • error handling error propagation step errors basic step error preserves message and stack trace
🐘 Local Postgres (3 failed)

hono-stable (2 failed):

  • fibonacciWorkflow - recursive workflow composition via start() | wrun_01KNV9MM07X6HSY79P4D2J57H0
  • health check (queue-based) - workflow and step endpoints respond to health check messages

nextjs-turbopack-stable (1 failed):

  • error handling error propagation step errors basic step error preserves message and stack trace
🌍 Community Worlds (76 failed)

mongodb (7 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNV99D9SPNC0XSC20850WJ5X
  • webhookWorkflow | wrun_01KNV99SSWAHFP39DP53D9HFTN
  • fetchWorkflow | wrun_01KNV9DE5PBG9TKMRBDA9FY589
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNV9HVRYV00T961R8A1E2QYV
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • health check (CLI) - workflow health command reports healthy endpoints
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNV9SDPW9FHXX8PNMHXMTAMQ

redis (7 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNV99D9SPNC0XSC20850WJ5X
  • webhookWorkflow | wrun_01KNV99SSWAHFP39DP53D9HFTN
  • fetchWorkflow | wrun_01KNV9DE5PBG9TKMRBDA9FY589
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNV9HVRYV00T961R8A1E2QYV
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • health check (CLI) - workflow health command reports healthy endpoints
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNV9SDPW9FHXX8PNMHXMTAMQ

turso (62 failed):

  • addTenWorkflow | wrun_01KNV985ZN5H9Q2Z1E80DW2EV3
  • addTenWorkflow | wrun_01KNV985ZN5H9Q2Z1E80DW2EV3
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KNV9A0Q33340WKAA0VS5VREK
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KNV98D6CEPHQH8PKNCKAWNNQ
  • promiseRaceWorkflow | wrun_01KNV98JNY8MTASZAS80W7FHY0
  • promiseAnyWorkflow | wrun_01KNV98MYYNMAJG004BRTAPTNX
  • importedStepOnlyWorkflow | wrun_01KNV9ADKP9MEX75X6M5Z8DK0D
  • hookWorkflow | wrun_01KNV991210JWWR8AHJDHNT73G
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KNV99D9SPNC0XSC20850WJ5X
  • webhookWorkflow | wrun_01KNV99SSWAHFP39DP53D9HFTN
  • sleepingWorkflow | wrun_01KNV9A0B5956WTYMKK7N2X0RQ
  • parallelSleepWorkflow | wrun_01KNV9ACHDHN1KX2ZCK0F4J34T
  • nullByteWorkflow | wrun_01KNV9AG02Z7TCQQ29TS9ZPR24
  • workflowAndStepMetadataWorkflow | wrun_01KNV9AJC5BSD298N26KZM3DSQ
  • fetchWorkflow | wrun_01KNV9DE5PBG9TKMRBDA9FY589
  • promiseRaceStressTestWorkflow | wrun_01KNV9DHWJVFR6H142C0H5A6G0
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • error handling not registered WorkflowNotRegisteredError fails the run when workflow does not exist
  • error handling not registered StepNotRegisteredError fails the step but workflow can catch it
  • error handling not registered StepNotRegisteredError fails the run when not caught in workflow
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_01KNV9H5ZCRHEHN0QZMVKQJH6C
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KNV9HVRYV00T961R8A1E2QYV
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KNV9JJTCYGK8H7Y8S1JWSJF6
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KNV9K7KS9RN3YXE5QSNJ9W5V
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KNV9KH6N1YZ3A7MYC5EA5MB7
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KNV9KQ4MVA7BYPBDY5R9VA81
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KNV9KSF03GSCWXNM2JGBDRHS
  • runClassSerializationWorkflow - Run instances serialize across workflow/step boundaries | wrun_01KNV9M54RK9YY13A0ANYZYRYD
  • startFromWorkflow - calling start() directly inside a workflow function with hook communication | wrun_01KNV9MGTV0A0D00B1J0K86HGN
  • fibonacciWorkflow - recursive workflow composition via start() | wrun_01KNV9MM07X6HSY79P4D2J57H0
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • health check (CLI) - workflow health command reports healthy endpoints
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KNV9N396QJ9X60D63H3CMY6Z
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KNV9NA0SJGB6JBMWYEA0G543
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KNV9NH1TGP0N3KP1ES74DWPP
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KNV9NR86XXBAP03H13VQGXY8
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KNV9NZPZHXRNR7H31JEVJJP7
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KNV9P70C6S90B67211E0QE1G
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KNV9PEAS3BYSPR8S852RX1N3
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KNV9PSC1GB0P3HF0C3J253NE
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KNV9Q1WJWDA0WPMFNKYKK2T7
  • cancelRun - cancelling a running workflow | wrun_01KNV9Q91M06VQCR2HS5H61TTA
  • cancelRun via CLI - cancelling a running workflow | wrun_01KNV9QK9GNJW1JCDW1GPT9TWA
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep | wrun_01KNV9R1DQS83RS9GDVVJNCHYY
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KNV9RPWTADXJBD3TVQQW7VZ9
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KNV9S1QRFCANEATFNP020F0F
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KNV9S8TDWEX91H08PRH3GQNY
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KNV9SB4EFAA89VSSWJQ41FMG
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KNV9SDPW9FHXX8PNMHXMTAMQ
  • getterStepWorkflow - getter functions with "use step" directive | wrun_01KNV9SKWQQ1306VXKQKGQXG84

Details by Category

❌ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 85 0 7
✅ example 85 0 7
✅ express 85 0 7
✅ fastify 85 0 7
✅ hono 85 0 7
❌ nextjs-turbopack 89 1 2
✅ nextjs-webpack 90 0 2
✅ nitro 85 0 7
✅ nuxt 85 0 7
✅ sveltekit 85 0 7
✅ vite 85 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 78 0 14
✅ hono-stable 78 0 14
✅ nextjs-turbopack-canary 65 0 27
✅ nextjs-turbopack-stable 84 0 8
✅ nextjs-webpack-canary 65 0 27
✅ nextjs-webpack-stable 84 0 8
✅ nitro-stable 78 0 14
✅ nuxt-stable 78 0 14
✅ sveltekit-stable 78 0 14
✅ vite-stable 78 0 14
❌ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 78 0 14
✅ express-stable 78 0 14
✅ fastify-stable 78 0 14
✅ hono-stable 78 0 14
✅ nextjs-turbopack-canary 65 0 27
❌ nextjs-turbopack-stable 83 1 8
✅ nextjs-webpack-canary 65 0 27
✅ nextjs-webpack-stable 84 0 8
✅ nitro-stable 78 0 14
✅ nuxt-stable 78 0 14
✅ sveltekit-stable 78 0 14
✅ vite-stable 78 0 14
❌ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 78 0 14
✅ express-stable 78 0 14
✅ fastify-stable 78 0 14
❌ hono-stable 76 2 14
✅ nextjs-turbopack-canary 65 0 27
❌ nextjs-turbopack-stable 83 1 8
✅ nextjs-webpack-canary 65 0 27
✅ nextjs-webpack-stable 84 0 8
✅ nitro-stable 78 0 14
✅ nuxt-stable 78 0 14
✅ sveltekit-stable 78 0 14
✅ vite-stable 78 0 14
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 84 0 8
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 6 0 0
❌ mongodb 58 7 8
✅ redis-dev 6 0 0
❌ redis 58 7 8
✅ turso-dev 6 0 0
❌ turso 3 62 8
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 78 0 14
✅ e2e-local-postgres-nest-stable 78 0 14
✅ e2e-local-prod-nest-stable 78 0 14

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@pranaygp pranaygp changed the title Revert "Revert \"Add support for calling start() inside workflow functions\"" Revert Revert "Add support for calling start() inside workflow functions" Mar 23, 2026
@VaguelySerious VaguelySerious changed the title Revert Revert "Add support for calling start() inside workflow functions" Add support for calling start() inside workflow functions (second attempt) Mar 24, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Re-enables calling start() from workflow/api directly inside "use workflow" functions by routing the call through internal built-in steps, with Run objects working in workflow VM context (step-backed getters/methods) and improved observability UI hydration/rendering for run references.

Changes:

  • Add workflow-context start() delegation via WORKFLOW_START, backed by a built-in start step and a workflow-VM WorkflowRun proxy class.
  • Extend serialization/hydration to support Run/WorkflowRun across boundaries and render Run references as clickable UI elements.
  • Update builders, plugin behavior/docs, and add unit + e2e coverage for startFromWorkflow and recursive fibonacciWorkflow.

Reviewed changes

Copilot reviewed 38 out of 38 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
workbench/nextjs-turbopack/app/workflows/definitions.ts Adds default args for new e2e workflows.
workbench/example/workflows/99_e2e.ts Adds startFromWorkflow and recursive fibonacciWorkflow workflows for e2e.
skills/workflow/SKILL.md Updates skill guidance to reflect start() support inside workflows.
packages/workflow/src/runtime.ts Re-exports getRun and start from core runtime for rewritten step imports.
packages/workflow/src/internal/builtins.ts Adds built-in start step and Run.* step-backed static methods.
packages/workflow/src/api-workflow.ts Routes start() in workflow bundle via WORKFLOW_START injection.
packages/web/app/components/run-detail-view.tsx Adds run-ref click navigation wiring.
packages/web-shared/src/lib/hydration.ts Exposes RunRef helpers for UI hydration.
packages/web-shared/src/components/workflow-traces/trace-span-construction.ts Improves span naming fallback behavior.
packages/web-shared/src/components/workflow-trace-view.tsx Plumbs onRunClick and resets selection on run change.
packages/web-shared/src/components/ui/data-inspector.tsx Adds RunRef rendering + “opaque ref” collapsing + click contexts.
packages/web-shared/src/components/sidebar/entity-detail-panel.tsx Passes onRunClick into detail panel rendering.
packages/web-shared/src/components/sidebar/attribute-panel.tsx Adds Run click context and improves stepName display fallback.
packages/web-shared/src/components/run-trace-view.tsx Threads onRunClick through trace view components.
packages/swc-plugin-workflow/transform/src/lib.rs Removes __builtin* step-id special casing to use normal IDs.
packages/swc-plugin-workflow/spec.md Updates spec examples to include builtins module-specifier IDs.
packages/next/src/builder-deferred.ts Rewrites bare specifiers (incl. dynamic import) and ensures builtins are included in step files.
packages/core/src/workflow/start.ts Implements workflow-VM createStart() using internal start built-in step.
packages/core/src/workflow/start.test.ts Adds unit tests for workflow-context start() behavior and option validation.
packages/core/src/workflow/run.ts Adds workflow-VM WorkflowRun proxy delegating to built-in Run steps.
packages/core/src/workflow/run.test.ts Adds unit tests asserting step delegation naming/arguments.
packages/core/src/workflow/builtin-step-id.ts Adds helper to construct built-in step IDs.
packages/core/src/workflow.ts Injects WORKFLOW_START, registers WorkflowRun, and updates response builtins to qualified IDs.
packages/core/src/symbols.ts Adds WORKFLOW_START symbol.
packages/core/src/serialization.ts Adds Run reducer/reviver using __serializable marker + class registry.
packages/core/src/serialization-format.ts Adds RunRef marker/type + reviver mapping Run → RunRef for o11y.
packages/core/src/runtime/step-handler.ts Registers runtime Run class in host class registry for Run reviver.
packages/core/src/runtime/start.ts Delegates start() to injected workflow implementation when in workflow VM.
packages/core/src/runtime/run.ts Adds Run.__serializable marker for serialization.
packages/core/src/private.ts Extends builtin step aliasing to accept fully-qualified builtins step IDs.
packages/core/e2e/e2e.test.ts Adds e2e tests validating workflow-context start() and recursion.
docs/proxy.ts Formatting-only string quote normalization.
docs/lib/ai-agent-detection.ts Formatting-only string quote normalization.
docs/content/docs/foundations/starting-workflows.mdx Documents calling start() inside workflow functions and recursive patterns.
docs/content/docs/foundations/common-patterns.mdx Updates patterns docs to use direct start() in workflows.
docs/content/docs/api-reference/workflow-api/start.mdx Updates API reference to include workflow-context usage.
AGENTS.md Updates local e2e instructions to include WORKFLOW_PUBLIC_MANIFEST=1.
.changeset/start-in-workflow.md Declares patch release for workflow-context start() support.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Add 'use step' to start() so it can be called directly from workflow
code. The SWC compiler strips the function body in workflow mode and
replaces it with a step proxy. When called from a workflow:

1. The workflow function reference is serialized via WorkflowFunction
   reducer (serializes { workflowId })
2. start() executes in the step context with full Node.js access
3. The returned Run is serialized via WORKFLOW_SERIALIZE and deserialized
   back in the workflow VM
4. Run getters (.status, .returnValue, etc.) are 'use step' getters
   that each execute as separate steps

Also re-exports start from @workflow/core/runtime/start in api-workflow.ts
instead of using a throwing stub, adds e2e tests for startFromWorkflow
(with hook communication) and fibonacciWorkflow (recursive composition).
… duplicate classes

Files belonging to packages (detected by walking up to find a
package.json with a name field) are imported via relative path
instead of being copied to __workflow_step_files__/. Copying creates
a second module instance which breaks JS native private field (#)
brand checks when the runtime creates instances from one copy and
the step handler accesses fields from the other.
…t all package step files

Regular package step files (like fetch) must still be copied to ensure
the SWC loader registers them. Only serde class files from packages are
excluded from copying since those define classes with JS native private
fields (#) that break when duplicated.
…d of full copies

For package files that define serde classes (like Run), generate a thin
wrapper that imports the original class and registers steps/classes from
the manifest. This avoids duplicating the class definition (which breaks
JS native private field brand checks) while still registering all step
functions and the class in the serialization registry.

Regular package step files (like fetch) are still copied as before.
… step mode

Instead of copying package serde+step files (which creates duplicate
classes with #private brand check issues) or generating fragile wrappers,
add the original file paths to a shared forceStepModeFiles set. The
loader checks this set and transforms those files in step mode directly,
so the SWC plugin generates proper step registrations on the original
class — no duplication, no reimplemented registration logic.
…just copies

The loader now selects step mode for any file that has 'use step'
directives or serde patterns, regardless of whether it's a deferred
step copy. Step mode is a superset of client mode — the only addition
is step registry IIFEs, which are harmless for non-step consumers.

This means package serde+step files (like Run) no longer need to be
copied to get step registrations. They're imported directly in the
step route and the loader transforms the original file in step mode.
One class instance, no duplication, no wrapper generation.
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