Skip to content

[v5 only] docs: restore start-in-workflow documentation#1803

Open
pranaygp wants to merge 3 commits into
mainfrom
pranaygp/codex/start-in-workflow-docs
Open

[v5 only] docs: restore start-in-workflow documentation#1803
pranaygp wants to merge 3 commits into
mainfrom
pranaygp/codex/start-in-workflow-docs

Conversation

@pranaygp
Copy link
Copy Markdown
Contributor

@pranaygp pranaygp commented Apr 17, 2026

Summary

  • restore the missing docs for calling start() directly inside workflow functions
  • document background child workflow execution and recursive/self-chaining patterns
  • add an empty changeset file to satisfy repo PR policy without shipping additional runtime changes

Note

  • this feature is implemented in Workflow v5 only; when these docs are ported through the versioned docs flow, keep them behind the docs version switcher and do not backport this content into earlier versions

Testing

  • not run (docs-only change; this worktree does not have installed node_modules)

@pranaygp pranaygp requested a review from a team as a code owner April 17, 2026 19:53
Copilot AI review requested due to automatic review settings April 17, 2026 19:53
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 17, 2026

🦋 Changeset detected

Latest commit: f3d4f42

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 17, 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 17, 2026 8:03pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment Apr 17, 2026 8:03pm
example-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-astro-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-express-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-fastify-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-hono-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-nitro-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-nuxt-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-sveltekit-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workbench-vite-workflow Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workflow-docs Ready Ready Preview, Comment, Open in v0 Apr 17, 2026 8:03pm
workflow-swc-playground Ready Ready Preview, Comment Apr 17, 2026 8:03pm
workflow-web Ready Ready Preview, Comment Apr 17, 2026 8:03pm

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 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 🥇 Nitro 0.037s (-14.6% 🟢) 1.004s (~) 0.968s 10 1.00x
💻 Local Express 0.044s (~) 1.005s (~) 0.961s 10 1.20x
💻 Local Next.js (Turbopack) 0.046s 1.005s 0.959s 10 1.25x
🐘 Postgres Express 0.046s (-20.0% 🟢) 1.011s (~) 0.964s 10 1.26x
🐘 Postgres Next.js (Turbopack) 0.056s 1.009s 0.953s 10 1.53x
🐘 Postgres Nitro 0.060s (-37.0% 🟢) 1.009s (-3.2%) 0.949s 10 1.63x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 0.230s (-8.5% 🟢) 1.923s (-17.6% 🟢) 1.693s 10 1.00x
▲ Vercel Express 0.244s (+3.7%) 2.297s (+7.6% 🔺) 2.053s 10 1.06x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack) | Express

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.099s (-2.8%) 2.005s (~) 0.905s 10 1.00x
🐘 Postgres Express 1.116s (-2.6%) 2.011s (~) 0.894s 10 1.02x
💻 Local Next.js (Turbopack) 1.123s 2.006s 0.883s 10 1.02x
💻 Local Express 1.128s (~) 2.005s (~) 0.877s 10 1.03x
🐘 Postgres Next.js (Turbopack) 1.144s 2.009s 0.864s 10 1.04x
🐘 Postgres Nitro 1.147s (+0.6%) 2.010s (~) 0.863s 10 1.04x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.914s (+2.1%) 3.674s (-3.5%) 1.760s 10 1.00x
▲ Vercel Next.js (Turbopack) 2.097s (+3.1%) 3.572s (-6.8% 🟢) 1.474s 10 1.10x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express | Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 10.634s (-2.8%) 11.023s (~) 0.388s 3 1.00x
🐘 Postgres Express 10.698s (-2.4%) 11.026s (~) 0.328s 3 1.01x
🐘 Postgres Next.js (Turbopack) 10.825s 11.020s 0.195s 3 1.02x
💻 Local Next.js (Turbopack) 10.842s 11.022s 0.180s 3 1.02x
🐘 Postgres Nitro 10.865s (~) 11.017s (~) 0.152s 3 1.02x
💻 Local Express 10.919s (~) 11.023s (~) 0.104s 3 1.03x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 18.085s (+6.5% 🔺) 20.081s (~) 1.996s 2 1.00x
▲ Vercel Next.js (Turbopack) 18.200s (+5.1% 🔺) 19.815s (+2.1%) 1.616s 2 1.01x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express | Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 14.081s (-3.4%) 15.024s (~) 0.943s 4 1.00x
💻 Local Nitro 14.240s (-5.5% 🟢) 15.029s (-6.2% 🟢) 0.789s 4 1.01x
🐘 Postgres Next.js (Turbopack) 14.433s 15.022s 0.589s 4 1.02x
🐘 Postgres Nitro 14.509s (-0.6%) 15.022s (~) 0.512s 4 1.03x
💻 Local Next.js (Turbopack) 14.579s 15.029s 0.450s 4 1.04x
💻 Local Express 14.961s (~) 15.030s (~) 0.068s 4 1.06x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 32.258s (-38.6% 🟢) 33.944s (-37.8% 🟢) 1.686s 2 1.00x
▲ Vercel Express 34.708s (-31.0% 🟢) 36.764s (-30.1% 🟢) 2.056s 2 1.08x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack) | Express

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 13.078s (-6.6% 🟢) 13.734s (-5.9% 🟢) 0.657s 7 1.00x
🐘 Postgres Next.js (Turbopack) 13.760s 14.020s 0.260s 7 1.05x
🐘 Postgres Nitro 13.909s (~) 14.164s (-1.0%) 0.255s 7 1.06x
💻 Local Nitro 14.958s (-10.9% 🟢) 15.027s (-11.8% 🟢) 0.069s 6 1.14x
💻 Local Next.js (Turbopack) 16.101s 16.697s 0.596s 6 1.23x
💻 Local Express 16.620s (~) 17.031s (~) 0.411s 6 1.27x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 57.867s (-85.3% 🟢) 58.931s (-85.1% 🟢) 1.063s 2 1.00x
▲ Vercel Express 58.194s (-52.0% 🟢) 60.327s (-51.2% 🟢) 2.133s 2 1.01x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack) | Express

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.207s (-4.2%) 2.009s (~) 0.802s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.235s 2.009s 0.774s 15 1.02x
🐘 Postgres Nitro 1.256s (-1.4%) 2.010s (~) 0.753s 15 1.04x
💻 Local Next.js (Turbopack) 1.521s 2.005s 0.485s 15 1.26x
💻 Local Express 1.547s (+3.9%) 2.006s (~) 0.460s 15 1.28x
💻 Local Nitro 1.865s (+14.3% 🔺) 2.392s (+15.3% 🔺) 0.527s 13 1.54x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.496s (-12.7% 🟢) 4.297s (-7.0% 🟢) 1.802s 7 1.00x
▲ Vercel Next.js (Turbopack) 2.705s (-20.4% 🟢) 4.074s (-17.4% 🟢) 1.368s 8 1.08x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express | Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.272s (-3.7%) 3.008s (~) 0.735s 10 1.00x
🐘 Postgres Nitro 2.334s (-0.7%) 3.008s (~) 0.674s 10 1.03x
🐘 Postgres Next.js (Turbopack) 2.413s 3.008s 0.595s 10 1.06x
💻 Local Nitro 2.649s (-15.7% 🟢) 3.008s (-22.6% 🟢) 0.359s 10 1.17x
💻 Local Express 2.901s (-1.7%) 3.209s (-7.1% 🟢) 0.308s 10 1.28x
💻 Local Next.js (Turbopack) 2.936s 3.565s 0.629s 9 1.29x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.235s (-38.3% 🟢) 3.688s (-27.8% 🟢) 1.453s 9 1.00x
▲ Vercel Next.js (Turbopack) 3.083s (-56.6% 🟢) 4.713s (-47.1% 🟢) 1.631s 7 1.38x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express | Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.383s (-3.0%) 4.011s (~) 0.628s 8 1.00x
🐘 Postgres Nitro 3.483s (~) 4.013s (~) 0.530s 8 1.03x
🐘 Postgres Next.js (Turbopack) 3.655s 4.012s 0.356s 8 1.08x
💻 Local Nitro 6.940s (-16.9% 🟢) 7.517s (-16.7% 🟢) 0.577s 4 2.05x
💻 Local Next.js (Turbopack) 7.905s 8.522s 0.617s 4 2.34x
💻 Local Express 8.199s (-1.7%) 9.025s (~) 0.826s 4 2.42x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.692s (-36.5% 🟢) 4.487s (-26.8% 🟢) 1.795s 7 1.00x
▲ Vercel Next.js (Turbopack) 4.072s (-54.3% 🟢) 5.283s (-51.8% 🟢) 1.211s 6 1.51x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express | Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 1.190s (-5.4% 🟢) 2.007s (~) 0.818s 15 1.00x
🐘 Postgres Next.js (Turbopack) 1.216s 2.008s 0.793s 15 1.02x
🐘 Postgres Nitro 1.257s (~) 2.008s (~) 0.751s 15 1.06x
💻 Local Nitro 1.476s (-20.9% 🟢) 2.006s (-14.3% 🟢) 0.530s 15 1.24x
💻 Local Next.js (Turbopack) 1.528s 2.006s 0.478s 15 1.28x
💻 Local Express 1.550s (-18.1% 🟢) 2.007s (-15.1% 🟢) 0.456s 15 1.30x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.070s (-29.4% 🟢) 3.532s (-23.9% 🟢) 1.462s 9 1.00x
▲ Vercel Express 2.361s (-8.5% 🟢) 4.056s (-6.7% 🟢) 1.695s 8 1.14x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack) | Express

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.265s (-3.3%) 3.009s (~) 0.744s 10 1.00x
🐘 Postgres Nitro 2.334s (~) 3.010s (~) 0.676s 10 1.03x
🐘 Postgres Next.js (Turbopack) 2.420s 3.010s 0.590s 10 1.07x
💻 Local Nitro 2.694s (-12.1% 🟢) 3.008s (-22.6% 🟢) 0.314s 10 1.19x
💻 Local Express 3.047s (-2.7%) 3.760s (~) 0.713s 8 1.35x
💻 Local Next.js (Turbopack) 3.117s 3.676s 0.559s 9 1.38x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.010s (-4.2%) 4.678s (+3.4%) 1.668s 7 1.00x
▲ Vercel Express 3.200s (~) 5.100s (+6.4% 🔺) 1.900s 6 1.06x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack) | Express

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.389s (-3.1%) 4.009s (~) 0.620s 8 1.00x
🐘 Postgres Nitro 3.482s (~) 4.012s (~) 0.530s 8 1.03x
🐘 Postgres Next.js (Turbopack) 3.651s 4.009s 0.358s 8 1.08x
💻 Local Nitro 7.396s (-19.1% 🟢) 8.017s (-20.0% 🟢) 0.620s 4 2.18x
💻 Local Express 8.671s (-1.5%) 9.026s (-2.7%) 0.355s 4 2.56x
💻 Local Next.js (Turbopack) 8.962s 9.520s 0.558s 4 2.64x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.609s (-59.3% 🟢) 4.579s (-44.0% 🟢) 1.969s 7 1.00x
▲ Vercel Next.js (Turbopack) 3.451s (-48.9% 🟢) 5.037s (-41.0% 🟢) 1.586s 6 1.32x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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.605s (-27.9% 🟢) 1.006s (-1.6%) 0.401s 60 1.00x
💻 Local Nitro 0.702s (-28.4% 🟢) 1.004s (-8.2% 🟢) 0.302s 60 1.16x
🐘 Postgres Next.js (Turbopack) 0.750s 1.006s 0.256s 60 1.24x
🐘 Postgres Nitro 0.821s (~) 1.006s (~) 0.185s 60 1.36x
💻 Local Next.js (Turbopack) 0.839s 1.022s 0.183s 59 1.39x
💻 Local Express 0.996s (+1.2%) 1.309s (+21.7% 🔺) 0.313s 46 1.65x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 10.272s (-46.0% 🟢) 12.087s (-43.3% 🟢) 1.815s 5 1.00x
▲ Vercel Next.js (Turbopack) 10.356s (-28.6% 🟢) 12.650s (-21.4% 🟢) 2.294s 5 1.01x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express | 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.435s (-27.4% 🟢) 2.008s (-11.1% 🟢) 0.573s 45 1.00x
🐘 Postgres Next.js (Turbopack) 1.859s 2.053s 0.194s 44 1.30x
🐘 Postgres Nitro 1.876s (-2.7%) 2.051s (-2.3%) 0.175s 45 1.31x
💻 Local Nitro 2.296s (-24.4% 🟢) 3.008s (-20.0% 🟢) 0.712s 30 1.60x
💻 Local Next.js (Turbopack) 2.668s 3.008s 0.340s 30 1.86x
💻 Local Express 3.223s (+6.9% 🔺) 3.884s (+8.3% 🔺) 0.661s 24 2.25x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 29.607s (-14.3% 🟢) 32.066s (-12.9% 🟢) 2.459s 3 1.00x
▲ Vercel Next.js (Turbopack) 35.134s (-29.5% 🟢) 36.951s (-28.5% 🟢) 1.816s 3 1.19x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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.962s (-25.8% 🟢) 3.193s (-26.9% 🟢) 0.231s 38 1.00x
🐘 Postgres Next.js (Turbopack) 3.800s 4.075s 0.276s 30 1.28x
🐘 Postgres Nitro 4.030s (-1.8%) 4.704s (+2.2%) 0.674s 26 1.36x
💻 Local Nitro 7.429s (-20.1% 🟢) 8.016s (-20.0% 🟢) 0.587s 15 2.51x
💻 Local Next.js (Turbopack) 8.676s 9.089s 0.413s 14 2.93x
💻 Local Express 9.156s (-0.6%) 9.787s (-2.3%) 0.631s 13 3.09x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 76.856s (-40.9% 🟢) 78.782s (-40.4% 🟢) 1.926s 2 1.00x
▲ Vercel Next.js (Turbopack) 79.484s (-25.8% 🟢) 81.246s (-25.4% 🟢) 1.762s 2 1.03x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Express | Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.218s (-22.8% 🟢) 1.007s (~) 0.789s 60 1.00x
🐘 Postgres Next.js (Turbopack) 0.252s 1.007s 0.755s 60 1.16x
🐘 Postgres Nitro 0.284s (~) 1.007s (~) 0.723s 60 1.30x
💻 Local Next.js (Turbopack) 0.551s 1.004s 0.454s 60 2.53x
💻 Local Nitro 0.577s (-4.6%) 1.004s (-1.7%) 0.427s 60 2.65x
💻 Local Express 0.681s (+21.5% 🔺) 1.096s (+9.1% 🔺) 0.415s 55 3.12x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 1.618s (-20.0% 🟢) 3.383s (-10.8% 🟢) 1.765s 18 1.00x
▲ Vercel Express 1.619s (-17.2% 🟢) 3.026s (-16.8% 🟢) 1.407s 20 1.00x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack) | Express

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 0.363s (-28.9% 🟢) 1.006s (~) 0.644s 90 1.00x
🐘 Postgres Next.js (Turbopack) 0.475s 1.006s 0.530s 90 1.31x
🐘 Postgres Nitro 0.506s (+2.0%) 1.007s (~) 0.500s 90 1.40x
💻 Local Nitro 2.443s (-3.8%) 3.007s (~) 0.564s 30 6.74x
💻 Local Express 2.510s (~) 3.008s (~) 0.498s 30 6.93x
💻 Local Next.js (Turbopack) 2.609s 3.008s 0.399s 30 7.20x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.829s (-7.1% 🟢) 4.530s (-5.8% 🟢) 1.701s 20 1.00x
▲ Vercel Next.js (Turbopack) 3.213s (-9.1% 🟢) 4.649s (-10.5% 🟢) 1.435s 20 1.14x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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 🥇 Express 0.574s (-29.9% 🟢) 1.006s (-1.1%) 0.432s 120 1.00x
🐘 Postgres Next.js (Turbopack) 0.761s 1.023s 0.262s 118 1.33x
🐘 Postgres Nitro 0.820s (+3.8%) 1.009s (~) 0.189s 119 1.43x
💻 Local Nitro 10.441s (-6.7% 🟢) 11.116s (-4.7%) 0.675s 11 18.20x
💻 Local Next.js (Turbopack) 10.831s 11.298s 0.467s 11 18.88x
💻 Local Express 11.153s (~) 11.754s (-1.6%) 0.601s 11 19.44x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 8.245s (+11.1% 🔺) 10.147s (+9.8% 🔺) 1.903s 12 1.00x
▲ Vercel Next.js (Turbopack) 8.321s (-19.4% 🟢) 10.133s (-17.5% 🟢) 1.812s 13 1.01x
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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 🥇 Nitro 0.140s (-34.5% 🟢) 1.004s (~) 0.011s (-12.8% 🟢) 1.018s (~) 0.878s 10 1.00x
🐘 Postgres Express 0.153s (-25.4% 🟢) 0.999s (~) 0.001s (-37.5% 🟢) 1.009s (~) 0.856s 10 1.09x
💻 Local Next.js (Turbopack) 0.169s 1.003s 0.013s 1.018s 0.850s 10 1.20x
🐘 Postgres Next.js (Turbopack) 0.195s 1.001s 0.001s 1.010s 0.816s 10 1.39x
💻 Local Express 0.201s (+0.7%) 1.004s (~) 0.012s (-0.8%) 1.018s (~) 0.818s 10 1.43x
🐘 Postgres Nitro 0.201s (-2.0%) 0.995s (-0.5%) 0.001s (-20.0% 🟢) 1.010s (~) 0.809s 10 1.43x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 1.563s (-37.6% 🟢) 3.059s (-25.2% 🟢) 1.133s (+17.9% 🔺) 4.644s (-16.9% 🟢) 3.081s 10 1.00x
▲ Vercel Next.js (Turbopack) 1.588s (-76.8% 🟢) 2.948s (-65.9% 🟢) 0.918s (+45.3% 🔺) 4.258s (-56.5% 🟢) 2.670s 10 1.02x
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: 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
🐘 Postgres 🥇 Express 0.516s (-18.1% 🟢) 1.007s (~) 0.005s (+34.5% 🔺) 1.023s (~) 0.507s 59 1.00x
🐘 Postgres Next.js (Turbopack) 0.610s 1.026s 0.004s 1.041s 0.431s 58 1.18x
🐘 Postgres Nitro 0.628s (+0.6%) 1.025s (+1.8%) 0.004s (-7.4% 🟢) 1.039s (+1.6%) 0.411s 58 1.22x
💻 Local Nitro 0.698s (-16.8% 🟢) 1.011s (~) 0.010s (+4.7%) 1.115s (~) 0.417s 54 1.35x
💻 Local Express 0.836s (+10.4% 🔺) 1.012s (-1.6%) 0.010s (+4.5%) 1.112s (+6.9% 🔺) 0.276s 57 1.62x
💻 Local Next.js (Turbopack) 0.995s 1.009s 0.010s 1.364s 0.369s 44 1.93x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 4.234s (-34.9% 🟢) 5.957s (-25.6% 🟢) 0.229s (-44.0% 🟢) 6.692s (-24.2% 🟢) 2.458s 9 1.00x
▲ Vercel Next.js (Turbopack) 5.182s (-69.4% 🟢) 6.517s (-64.3% 🟢) 0.188s (-11.1% 🟢) 7.154s (-62.2% 🟢) 1.971s 9 1.22x
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Express | Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Next.js (Turbopack) 0.911s 1.154s 0.000s 1.161s 0.250s 52 1.00x
🐘 Postgres Express 0.920s (-4.2%) 1.071s (-16.2% 🟢) 0.000s (-17.9% 🟢) 1.079s (-17.4% 🟢) 0.158s 56 1.01x
🐘 Postgres Nitro 0.965s (~) 1.274s (+2.1%) 0.000s (+2.1%) 1.285s (+2.2%) 0.320s 47 1.06x
💻 Local Nitro 1.199s (-2.0%) 2.019s (~) 0.001s (+433.3% 🔺) 2.021s (~) 0.822s 30 1.32x
💻 Local Next.js (Turbopack) 1.229s 2.017s 0.001s 2.020s 0.791s 30 1.35x
💻 Local Express 1.236s (+0.9%) 2.021s (~) 0.001s (+60.0% 🔺) 2.024s (~) 0.788s 30 1.36x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.662s (-28.8% 🟢) 3.853s (-24.5% 🟢) 0.000s (-100.0% 🟢) 4.312s (-22.0% 🟢) 1.650s 14 1.00x
▲ Vercel Next.js (Turbopack) 3.171s (-68.9% 🟢) 4.375s (-62.0% 🟢) 0.000s (NaN%) 4.788s (-60.3% 🟢) 1.617s 13 1.19x
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: 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 🥇 Express 1.649s (-6.9% 🟢) 2.070s (-5.0%) 0.000s (+Infinity% 🔺) 2.078s (-5.5% 🟢) 0.429s 29 1.00x
🐘 Postgres Nitro 1.760s (-1.8%) 2.065s (-3.6%) 0.000s (-100.0% 🟢) 2.092s (-3.8%) 0.332s 29 1.07x
🐘 Postgres Next.js (Turbopack) 1.787s 2.106s 0.000s 2.114s 0.327s 29 1.08x
💻 Local Nitro 3.554s (+4.9%) 4.032s (~) 0.001s (~) 4.035s (~) 0.481s 15 2.16x
💻 Local Next.js (Turbopack) 3.667s 4.030s 0.000s 4.034s 0.366s 15 2.22x
💻 Local Express 3.755s (+8.3% 🔺) 4.234s (+5.0%) 0.001s (+33.3% 🔺) 4.237s (+5.0%) 0.482s 15 2.28x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 3.929s (-14.3% 🟢) 5.227s (-13.2% 🟢) 0.000s (NaN%) 5.677s (-12.1% 🟢) 1.748s 11 1.00x
▲ Vercel Next.js (Turbopack) 4.425s (-21.2% 🟢) 5.729s (-17.9% 🟢) 0.000s (-100.0% 🟢) 6.201s (-17.8% 🟢) 1.775s 10 1.13x
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Express | Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Nitro 19/21
🐘 Postgres Express 20/21
▲ Vercel Express 15/21
Fastest World by Framework

Winner determined by most benchmark wins

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

📋 View full workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
❌ ▲ Vercel Production 944 1 67 1012
✅ 💻 Local Development 1018 0 86 1104
✅ 📦 Local Production 1018 0 86 1104
❌ 🐘 Local Postgres 1014 4 86 1104
✅ 🪟 Windows 92 0 0 92
✅ 📋 Other 258 0 18 276
Total 4344 5 343 4692

❌ Failed Tests

▲ Vercel Production (1 failed)

sveltekit (1 failed):

🐘 Local Postgres (4 failed)

hono-stable (2 failed):

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

nitro-stable (2 failed):

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

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 90 0 2
✅ nextjs-webpack 90 0 2
✅ nitro 85 0 7
✅ nuxt 85 0 7
❌ sveltekit 84 1 7
✅ vite 85 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 86 0 6
✅ express-stable 86 0 6
✅ fastify-stable 86 0 6
✅ hono-stable 86 0 6
✅ nextjs-turbopack-canary 73 0 19
✅ nextjs-turbopack-stable 92 0 0
✅ nextjs-webpack-canary 73 0 19
✅ nextjs-webpack-stable 92 0 0
✅ nitro-stable 86 0 6
✅ nuxt-stable 86 0 6
✅ sveltekit-stable 86 0 6
✅ vite-stable 86 0 6
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 86 0 6
✅ express-stable 86 0 6
✅ fastify-stable 86 0 6
✅ hono-stable 86 0 6
✅ nextjs-turbopack-canary 73 0 19
✅ nextjs-turbopack-stable 92 0 0
✅ nextjs-webpack-canary 73 0 19
✅ nextjs-webpack-stable 92 0 0
✅ nitro-stable 86 0 6
✅ nuxt-stable 86 0 6
✅ sveltekit-stable 86 0 6
✅ vite-stable 86 0 6
❌ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 86 0 6
✅ express-stable 86 0 6
✅ fastify-stable 86 0 6
❌ hono-stable 84 2 6
✅ nextjs-turbopack-canary 73 0 19
✅ nextjs-turbopack-stable 92 0 0
✅ nextjs-webpack-canary 73 0 19
✅ nextjs-webpack-stable 92 0 0
❌ nitro-stable 84 2 6
✅ nuxt-stable 86 0 6
✅ sveltekit-stable 86 0 6
✅ vite-stable 86 0 6
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 92 0 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 86 0 6
✅ e2e-local-postgres-nest-stable 86 0 6
✅ e2e-local-prod-nest-stable 86 0 6

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

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

Restores and expands documentation around starting workflows, especially using start() from within workflow functions (child workflows, background execution, and self-chaining/recursive patterns), and adds a no-op changeset to satisfy repo policy.

Changes:

  • Add docs/examples for calling start() inside workflow functions and explain determinism/step behavior.
  • Document recursive/self-chaining patterns and guidance for deploymentId: "latest".
  • Update “Common Patterns” background execution example to use start() directly (no wrapper step).

Reviewed changes

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

File Description
docs/content/docs/foundations/starting-workflows.mdx Adds a new “Starting Workflows from Workflow Functions” section plus recursion/self-chaining guidance.
docs/content/docs/foundations/common-patterns.mdx Updates background execution pattern to use start() directly inside workflows and adds a clarifying callout.
docs/content/docs/api-reference/workflow-api/start.mdx Updates “Good to Know” and adds an example for using start() inside workflow functions.
.changeset/fresh-rules-glow.md Adds a no-op/metadata-only changeset file per PR policy.

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

Comment on lines +53 to 55
* The `start()` function can be used in any context: runtime code (API routes, Server Actions), step functions, or directly inside workflow functions.
* This is different from calling workflow functions directly, which is the typical pattern in Next.js applications.
* The function returns immediately after enqueuing the workflow - it doesn't wait for the workflow to complete.
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The updated "Good to Know" bullet says start() can be used directly inside workflow functions, but the page frontmatter summary still states it's for starting runs "from outside a workflow function." Consider updating the frontmatter summary (and/or intro) so it doesn't contradict this expanded usage.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +4
---
---

Restore the missing documentation for calling `start()` directly inside workflow functions.
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

PR description says this is an empty changeset to satisfy policy, but this changeset includes descriptive body text. If the intent is to keep it a true no-op changeset (like other empty entries in .changeset/), consider removing the body text or updating the PR description to match what’s being added.

Copilot uses AI. Check for mistakes.
Comment on lines +102 to +105
When `start()` is called inside a workflow function, it automatically executes through an internal step to maintain deterministic replay. The returned `Run` object works just like it does outside workflows — properties like `.runId`, `.status`, `.returnValue`, and methods like `.cancel()` are all available. Each property access or method call executes as a separate step under the hood.

<Callout type="info">
Inside workflow functions, each `Run` property access (e.g., `run.status`, `run.returnValue`) triggers a workflow step. This means each access is recorded in the event log and replayed deterministically.
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The text here implies that accessing run.runId inside a workflow triggers a step, but runId is a plain string field on Run (not an async getter with a "use step" directive). Consider rewording to clarify that async Run getters/methods (e.g. status, returnValue, cancel(), getReadable()) run as steps, while runId does not.

Suggested change
When `start()` is called inside a workflow function, it automatically executes through an internal step to maintain deterministic replay. The returned `Run` object works just like it does outside workflows — properties like `.runId`, `.status`, `.returnValue`, and methods like `.cancel()` are all available. Each property access or method call executes as a separate step under the hood.
<Callout type="info">
Inside workflow functions, each `Run` property access (e.g., `run.status`, `run.returnValue`) triggers a workflow step. This means each access is recorded in the event log and replayed deterministically.
When `start()` is called inside a workflow function, it automatically executes through an internal step to maintain deterministic replay. The returned `Run` object works just like it does outside workflows — plain fields like `.runId` are available directly, while async getters/methods such as `.status`, `.returnValue`, `.cancel()`, and `.getReadable()` can also be used inside the workflow.
<Callout type="info">
Inside workflow functions, async `Run` getters and methods (for example `run.status`, `run.returnValue`, `run.cancel()`, and `run.getReadable()`) each trigger a workflow step. Plain fields like `run.runId` do not. These step-backed accesses are recorded in the event log and replayed deterministically.

Copilot uses AI. Check for mistakes.
</Callout>

<Callout type="info">
Inside workflow functions, `start()` returns a full `Run` object. You can access `.runId`, `.status`, `.returnValue`, `.cancel()`, and other `Run` properties — each access executes as a separate step.
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

This callout lists .runId among Run properties that execute as steps inside workflow functions, but runId is a synchronous field on Run. Suggest updating the wording/examples to distinguish between synchronous fields (e.g. runId) and step-backed async getters/methods (e.g. status, returnValue, cancel()).

Suggested change
Inside workflow functions, `start()` returns a full `Run` object. You can access `.runId`, `.status`, `.returnValue`, `.cancel()`, and other `Run` properties — each access executes as a separate step.
Inside workflow functions, `start()` returns a full `Run` object. Some members are synchronous fields, such as `.runId`, which you can read immediately. Others, such as `.status`, `.returnValue`, and `.cancel()`, are step-backed async getters/methods that execute as separate steps inside the workflow.

Copilot uses AI. Check for mistakes.
@pranaygp pranaygp requested a review from TooTallNate April 17, 2026 20:01
@pranaygp pranaygp changed the title docs: restore start-in-workflow documentation [v5 only] docs: restore start-in-workflow documentation Apr 17, 2026
If you want the child workflow to run on the latest deployment rather than the current one, you can pass [`deploymentId: "latest"`](/docs/api-reference/workflow-api/start#using-deploymentid-latest) in the `start()` options. This is currently a Vercel-specific feature. Be aware that the child workflow's function name, file path, argument types, and return type must remain compatible across deployments — renaming the function or changing its location will change the workflow ID, and modifying expected inputs or outputs can cause serialization failures.
</Callout>

<Callout type="info">
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.

Documentation incorrectly states .runId executes as a separate workflow step, when it is actually a plain synchronous string field.

Fix on Vercel

Copy link
Copy Markdown
Member

@VaguelySerious VaguelySerious left a comment

Choose a reason for hiding this comment

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

Docs LGTM but again I think we should callout that it's only on v5. That will also help us split out the v4/v5 docs when we make that PR, and won't confuse stable users in the meantime

Copy link
Copy Markdown
Member

@TooTallNate TooTallNate left a comment

Choose a reason for hiding this comment

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

Review

Good restoration. Feature was added in #1133, reverted in #1475, re-added in #1491 (via the simpler 'use step' approach on the existing start() function). The docs accurately describe the re-introduced implementation.

Accuracy checks

All technical claims verified against the current implementation:

  • start() works inside workflows'use step' directive at packages/core/src/runtime/start.ts:122 makes it a step call inside a workflow context (#1491).
  • Returns a full Run objectRun has WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE at run.ts:73-82, so it survives the step boundary.
  • Each property access is a step — Verified for .status, .returnValue, .cancel(), .exists, .workflowName, .createdAt, .startedAt, .completedAt, .wakeUp(), .getReadable() — all have 'use step'.
  • returnValue polls every 1 second — Confirmed at run.ts:295-346 (#pollReturnValue with setTimeout(resolve, 1_000)).
  • Worker held alive during polling — True; since returnValue is a step, the step runtime holds the worker until the step resolves (or times out against the function's maxDuration).
  • Recursive/self-chaining pattern — Works because start() is fire-and-forget; parent completes after enqueueing the child.
  • deploymentId: "latest" — Supported (start.ts:158-165 resolves via world.resolveLatestDeploymentId).

Good calls

  • PR body's v5-only note + no-backport instruction is correct. The feature doesn't exist on stable (v4), so these docs would be wrong there. docs/content/ IS maintained on stable per AGENTS.md, so the backport action could pull this in if the backport-stable label is applied — but shouldn't be. Worth the explicit call-out in the PR body.
  • Polling caveat on returnValue is an important gotcha that users need to know. The suggested workaround (fire-and-forget + hooks for completion notification) is sound and matches the actual implementation of hooks.

Minor inaccuracy

See inline comment: "each property access or method call executes as a separate step" is slightly over-broad. .runId is a plain field (not a getter) and .readable is a non-'use step' getter. Only "most" properties are steps.

Changeset

The empty changeset is defensible here (docs-only change). Worth noting though: docs/content/docs/foundations/*.mdx is bundled into @workflow/core and workflow via prepack scripts, and docs/content/docs/api-reference/workflow-api/*.mdx is bundled into workflow. So the new docs won't reach npm consumers until the next release that bumps those packages for other reasons. If you want the docs to ship specifically with this PR, add workflow and @workflow/core as patch bumps. Otherwise the current empty changeset is fine — the new docs will ride along with the next beta release.

}
```

When `start()` is called inside a workflow function, it automatically executes through an internal step to maintain deterministic replay. The returned `Run` object works just like it does outside workflows — properties like `.runId`, `.status`, `.returnValue`, and methods like `.cancel()` are all available. Each property access or method call executes as a separate step under the hood.
Copy link
Copy Markdown
Member

@TooTallNate TooTallNate Apr 19, 2026

Choose a reason for hiding this comment

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

Minor: "Each property access or method call executes as a separate step under the hood" is slightly overbroad.

Verified against packages/core/src/runtime/run.ts:

Member Step?
runId No (plain field, line 87)
readable No (plain getter, line 244)
status Yes (line 184)
returnValue Yes (line 195)
cancel() Yes (line 154)
wakeUp() Yes (line 146)
exists Yes (line 166)
workflowName Yes (line 203)
createdAt / startedAt / completedAt Yes
getReadable() Yes (line 263)

runId being free is actually nice for users (e.g., logging run.runId inside a loop doesn't cost N steps). Consider rewording to something like: "Most Run properties — .status, .returnValue, .cancel(), etc. — execute as separate steps. Plain fields like .runId are free."

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