Skip to content

NestJS framework support#840

Merged
VaguelySerious merged 31 commits into
mainfrom
peter/nestjs
Jan 26, 2026
Merged

NestJS framework support#840
VaguelySerious merged 31 commits into
mainfrom
peter/nestjs

Conversation

@VaguelySerious
Copy link
Copy Markdown
Member

@VaguelySerious VaguelySerious commented Jan 23, 2026

Add workbench app + local world tests for NestJS.

Can be merged safely since tests pass and there's no public project or docs associated. Docs and Vercel prod tests will be added in #850 once this is merged

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jan 23, 2026

🦋 Changeset detected

Latest commit: fe8c6d1

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

This PR includes changesets to release 13 packages
Name Type
@workflow/nest Patch
@workflow/builders Patch
workflow Patch
@workflow/example-nest Patch
@workflow/astro Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/sveltekit Patch
@workflow/ai Patch
@workflow/docs-typecheck Patch
@workflow/world-testing 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
Copy link
Copy Markdown
Contributor

vercel Bot commented Jan 23, 2026

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

Project Deployment Review Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview, Comment Jan 26, 2026 9:22pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment Jan 26, 2026 9:22pm
example-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-astro-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-express-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-fastify-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-hono-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-nitro-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-nuxt-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-sveltekit-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
workbench-vite-workflow Ready Ready Preview, Comment Jan 26, 2026 9:22pm
1 Skipped Deployment
Project Deployment Review Updated (UTC)
workflow-docs Skipped Skipped Jan 26, 2026 9:22pm

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 23, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 457 0 38 495
❌ 💻 Local Development 416 2 32 450
✅ 📦 Local Production 418 0 32 450
✅ 🐘 Local Postgres 418 0 32 450
✅ 🪟 Windows 45 0 0 45
❌ 🌍 Community Worlds 31 161 0 192
✅ 📋 Other 123 0 12 135
Total 1908 163 146 2217

❌ Failed Tests

💻 Local Development (2 failed)

astro-stable (2 failed):

  • 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
🌍 Community Worlds (161 failed)

mongodb (40 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • 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()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

redis (40 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • 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()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

starter (41 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • 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()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • health check (CLI) - workflow health command reports healthy endpoints
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

turso (40 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • readableStreamWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • outputStreamWorkflow
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • 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()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 41 0 4
✅ example 41 0 4
✅ express 41 0 4
✅ fastify 41 0 4
✅ hono 41 0 4
✅ nextjs-turbopack 44 0 1
✅ nextjs-webpack 44 0 1
✅ nitro 41 0 4
✅ nuxt 41 0 4
✅ sveltekit 41 0 4
✅ vite 41 0 4
❌ 💻 Local Development
App Passed Failed Skipped
❌ astro-stable 39 2 4
✅ express-stable 41 0 4
✅ fastify-stable 41 0 4
✅ hono-stable 41 0 4
✅ nextjs-turbopack-stable 45 0 0
✅ nextjs-webpack-stable 45 0 0
✅ nitro-stable 41 0 4
✅ nuxt-stable 41 0 4
✅ sveltekit-stable 41 0 4
✅ vite-stable 41 0 4
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 41 0 4
✅ express-stable 41 0 4
✅ fastify-stable 41 0 4
✅ hono-stable 41 0 4
✅ nextjs-turbopack-stable 45 0 0
✅ nextjs-webpack-stable 45 0 0
✅ nitro-stable 41 0 4
✅ nuxt-stable 41 0 4
✅ sveltekit-stable 41 0 4
✅ vite-stable 41 0 4
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 41 0 4
✅ express-stable 41 0 4
✅ fastify-stable 41 0 4
✅ hono-stable 41 0 4
✅ nextjs-turbopack-stable 45 0 0
✅ nextjs-webpack-stable 45 0 0
✅ nitro-stable 41 0 4
✅ nuxt-stable 41 0 4
✅ sveltekit-stable 41 0 4
✅ vite-stable 41 0 4
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 45 0 0
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 0
❌ mongodb 5 40 0
✅ redis-dev 3 0 0
❌ redis 5 40 0
✅ starter-dev 3 0 0
❌ starter 4 41 0
✅ turso-dev 3 0 0
❌ turso 5 40 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 41 0 4
✅ e2e-local-postgres-nest-stable 41 0 4
✅ e2e-local-prod-nest-stable 41 0 4

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 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 🥇 Nitro 0.042s (-5.9% 🟢) 1.006s (~) 0.965s 10 1.00x
💻 Local Next.js (Turbopack) 0.043s (-13.2% 🟢) 1.021s (~) 0.978s 10 1.03x
💻 Local Express 0.043s (+3.8%) 1.008s (~) 0.965s 10 1.04x
🐘 Postgres Next.js (Turbopack) 0.159s (-4.8%) 1.020s (~) 0.861s 10 3.82x
🐘 Postgres Express 0.205s (-6.7% 🟢) 1.018s (~) 0.813s 10 4.91x
🐘 Postgres Nitro 0.242s (+16.8% 🔺) 1.014s (-0.7%) 0.772s 10 5.81x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 0.674s (-2.2%) 1.652s (+6.5% 🔺) 0.978s 10 1.00x
▲ Vercel Express 0.757s (+1.8%) 1.575s (-3.2%) 0.818s 10 1.12x
▲ Vercel Next.js (Turbopack) 0.800s (-8.8% 🟢) 1.838s (+8.5% 🔺) 1.038s 10 1.19x

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

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 1.093s (~) 2.014s (~) 0.921s 10 1.00x
💻 Local Nitro 1.112s (~) 2.006s (~) 0.893s 10 1.02x
💻 Local Express 1.116s (~) 2.008s (~) 0.892s 10 1.02x
🐘 Postgres Next.js (Turbopack) 1.910s (-0.5%) 2.116s (+4.9%) 0.207s 10 1.75x
🐘 Postgres Nitro 1.945s (-19.5% 🟢) 2.714s (-10.0% 🟢) 0.769s 10 1.78x
🐘 Postgres Express 2.292s (+1.8%) 3.014s (~) 0.722s 10 2.10x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.808s (-4.3%) 3.796s (+4.8%) 0.987s 10 1.00x
▲ Vercel Express 2.901s (-1.1%) 3.653s (-1.0%) 0.751s 10 1.03x
▲ Vercel Next.js (Turbopack) 2.908s (-5.3% 🟢) 3.888s (+1.7%) 0.980s 10 1.04x

🔍 Observability: Nitro | Express | 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.702s (~) 11.018s (~) 0.316s 5 1.00x
💻 Local Nitro 10.814s (~) 11.012s (~) 0.198s 5 1.01x
💻 Local Express 10.831s (~) 11.015s (~) 0.184s 5 1.01x
🐘 Postgres Next.js (Turbopack) 15.211s (+0.8%) 15.836s (~) 0.624s 5 1.42x
🐘 Postgres Nitro 15.751s (-22.3% 🟢) 16.029s (-23.8% 🟢) 0.279s 5 1.47x
🐘 Postgres Express 20.435s (+1.0%) 21.033s (~) 0.597s 5 1.91x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 22.525s (-2.8%) 23.586s (-1.7%) 1.061s 5 1.00x
▲ Vercel Next.js (Turbopack) 22.818s (-2.1%) 23.700s (-0.6%) 0.882s 5 1.01x
▲ Vercel Express 23.436s (+1.3%) 24.463s (+2.1%) 1.027s 5 1.04x

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

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.411s (~) 2.006s (~) 0.594s 15 1.00x
💻 Local Next.js (Turbopack) 1.414s (+2.9%) 2.014s (~) 0.600s 15 1.00x
💻 Local Express 1.429s (+2.1%) 2.006s (~) 0.577s 15 1.01x
🐘 Postgres Next.js (Turbopack) 2.110s (+22.6% 🔺) 2.755s (+32.4% 🔺) 0.645s 11 1.50x
🐘 Postgres Express 2.186s (-9.8% 🟢) 3.013s (~) 0.828s 10 1.55x
🐘 Postgres Nitro 2.305s (+2.8%) 3.013s (+16.0% 🔺) 0.708s 10 1.63x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.912s (-37.9% 🟢) 3.647s (-33.9% 🟢) 0.735s 9 1.00x
▲ Vercel Next.js (Turbopack) 2.991s (-29.2% 🟢) 3.815s (-23.1% 🟢) 0.824s 8 1.03x
▲ Vercel Nitro 3.135s (-29.0% 🟢) 4.043s (-23.2% 🟢) 0.907s 8 1.08x

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

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 2.456s (+2.8%) 3.063s (-6.6% 🟢) 0.607s 10 1.00x
💻 Local Nitro 2.467s (-1.7%) 3.043s (+0.7%) 0.576s 10 1.00x
💻 Local Express 2.496s (+2.7%) 3.041s (-1.7%) 0.545s 10 1.02x
🐘 Postgres Nitro 7.731s (-14.1% 🟢) 8.332s (-10.3% 🟢) 0.601s 4 3.15x
🐘 Postgres Express 8.712s (+17.8% 🔺) 9.305s (+15.2% 🔺) 0.592s 4 3.55x
🐘 Postgres Next.js (Turbopack) 12.196s (+14.5% 🔺) 12.692s (+15.0% 🔺) 0.496s 3 4.97x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.320s (-32.6% 🟢) 3.913s (-32.3% 🟢) 0.593s 8 1.00x
▲ Vercel Nitro 3.436s (-7.1% 🟢) 4.108s (-9.8% 🟢) 0.672s 8 1.03x
▲ Vercel Express 3.450s (-10.8% 🟢) 4.266s (-10.0% 🟢) 0.817s 8 1.04x

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

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 1.403s (~) 2.009s (~) 0.606s 15 1.00x
💻 Local Express 1.408s (-1.1%) 2.007s (~) 0.599s 15 1.00x
💻 Local Nitro 1.425s (~) 2.005s (~) 0.580s 15 1.02x
🐘 Postgres Express 2.111s (+3.6%) 2.511s (~) 0.400s 12 1.50x
🐘 Postgres Nitro 2.245s (+7.9% 🔺) 2.740s (+1.8%) 0.495s 11 1.60x
🐘 Postgres Next.js (Turbopack) 2.486s (+20.9% 🔺) 2.835s (+8.2% 🔺) 0.349s 11 1.77x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.826s (-22.5% 🟢) 3.852s (-12.3% 🟢) 1.025s 8 1.00x
▲ Vercel Express 2.990s (+2.5%) 3.799s (+3.6%) 0.809s 8 1.06x
▲ Vercel Next.js (Turbopack) 3.079s (+5.1% 🔺) 4.386s (+20.4% 🔺) 1.307s 7 1.09x

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

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 2.449s (-2.2%) 3.021s (-0.9%) 0.572s 10 1.00x
💻 Local Nitro 2.508s (-3.5%) 3.010s (~) 0.503s 10 1.02x
💻 Local Express 2.696s (+7.9% 🔺) 3.122s (+3.5%) 0.426s 10 1.10x
🐘 Postgres Express 10.477s (-7.1% 🟢) 11.022s (-5.9% 🟢) 0.544s 3 4.28x
🐘 Postgres Nitro 11.165s (-3.6%) 11.359s (-8.3% 🟢) 0.194s 3 4.56x
🐘 Postgres Next.js (Turbopack) 12.929s (-0.9%) 13.387s (-2.5%) 0.458s 3 5.28x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.384s (-18.7% 🟢) 4.012s (-16.8% 🟢) 0.628s 8 1.00x
▲ Vercel Nitro 3.402s (-4.7%) 4.006s (-6.6% 🟢) 0.605s 8 1.01x
▲ Vercel Express 3.527s (+5.1% 🔺) 4.123s (+1.7%) 0.596s 8 1.04x

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

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) 0.142s (+2.1%) 1.003s (~) 0.018s (+1.1%) 1.029s (~) 0.887s 10 1.00x
💻 Local Nitro 0.178s (-2.7%) 0.992s (~) 0.016s (+4.6%) 1.022s (~) 0.845s 10 1.25x
💻 Local Express 0.180s (+0.7%) 0.992s (~) 0.014s (+0.7%) 1.020s (~) 0.840s 10 1.27x
🐘 Postgres Next.js (Turbopack) 0.913s (-27.7% 🟢) 1.557s (~) 0.000s (+Infinity% 🔺) 1.616s (-11.2% 🟢) 0.703s 10 6.44x
🐘 Postgres Nitro 1.286s (-20.2% 🟢) 1.755s (-23.5% 🟢) 0.000s (+Infinity% 🔺) 2.013s (-16.7% 🟢) 0.727s 10 9.06x
🐘 Postgres Express 2.253s (-4.3%) 2.789s (+3.8%) 0.000s (NaN%) 3.015s (~) 0.762s 10 15.88x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.963s (-15.2% 🟢) 3.163s (-12.3% 🟢) 0.520s (-13.1% 🟢) 4.197s (-13.0% 🟢) 1.234s 10 1.00x
▲ Vercel Nitro 3.002s (-19.1% 🟢) 3.324s (-8.1% 🟢) 0.392s (-45.9% 🟢) 4.232s (-15.7% 🟢) 1.230s 10 1.01x
▲ Vercel Next.js (Turbopack) 3.019s (-24.5% 🟢) 3.352s (-18.5% 🟢) 0.747s (+38.1% 🔺) 4.616s (-12.5% 🟢) 1.597s 10 1.02x

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

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World 🥇 Fastest Framework Wins
💻 Local Next.js (Turbopack) 6/8
🐘 Postgres Next.js (Turbopack) 5/8
▲ Vercel Nitro 4/8
Fastest World by Framework

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 💻 Local 8/8
Next.js (Turbopack) 💻 Local 8/8
Nitro 💻 Local 8/8
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
  • 🌐 Starter: Community world (local development)
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)

📋 View full workflow run

This adds a @workflow/nest package that provides NestJS integration for the
Workflow DevKit. The integration includes:

- NestLocalBuilder: Extends BaseBuilder to generate workflow bundles in
  .nestjs/workflow directory
- WorkflowModule: NestJS module that can be imported via forRoot() with
  configuration options
- WorkflowController: Handles the /.well-known/workflow/v1/* endpoints for
  workflow execution, step execution, and webhooks

The workbench/nest example app demonstrates how to use the integration with
a standard NestJS application, including:
- API endpoints for triggering workflows and testing
- Integration with the e2e test suite
- Support for both ESM and body parsing

Also updates:
- Test matrix to include NestJS in CI
- Workflow package to export nest module
- Builders package to support 'nest' build target
- Biome config to support parameter decorators used by NestJS

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@socket-security
Copy link
Copy Markdown

socket-security Bot commented Jan 23, 2026

NestJS preserves source maps in production builds, so update the
hasStepSourceMaps() function to return true for NestJS.

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Add support for overriding the import path in generated _workflows.ts.
This is useful when workflows are compiled to a different location than
the source files, enabling future symlink support scenarios.

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
@@ -0,0 +1,11 @@
// Workflow-only file (no steps)
Copy link
Copy Markdown
Contributor

@pranaygp pranaygp Jan 23, 2026

Choose a reason for hiding this comment

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

all the workflows should be symlinks from example

Comment on lines +45 to +47
const relativeWorkflowsPath = runtimePath
? runtimePath
: path.relative(outputDir, workflowsDir).replace(/\\/g, '/');
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.

Am worried about this and if it's actually relevant or needed just for nest (spoke offline)

- Update resolve-symlinks.sh to handle src/workflows symlinks
- Replace committed workflow files with symlink to example/workflows
- Disable typeCheck in NestJS build (symlinked files cause path issues)
- Fix @repo path alias to resolve to repo root
- Remove redundant local paths-alias-test.ts file

The symlinks are resolved to real files by resolve-symlinks.sh in CI,
enabling workflow file sharing across workbenches while maintaining
compatibility with production builds.

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Comment thread workbench/nest/tsconfig.json
Comment thread workbench/nest/.swcrc Outdated
},
"experimental": {
"plugins": [
["@workflow/swc-plugin", { "mode": "client" }]
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.

erm I don't think nestjs users should have to setup the swc plugin explicitly. we don't/shouldn't do this on any of the other frameworks

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.

the swc plugin should be configured by the framework integration (see the other builders)

Comment thread workbench/nest/package.json Outdated
"@types/express": "^5.0.0",
"@types/node": "^22.10.7",
"@workflow/ai": "workspace:*",
"@workflow/swc-plugin": "workspace:*",
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.

this shouldn't be a dep. workflow (and henceworkflow/nest) is all you need

Copy link
Copy Markdown
Contributor

@pranaygp pranaygp left a comment

Choose a reason for hiding this comment

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

the user shouldn't be setting up an swcrc. that's to be configured by the builders. infact I believe we ignore any project level swcrc in next for example :)

VaguelySerious and others added 9 commits January 23, 2026 14:36
The --runtime-path option was added for potential symlink scenarios but
is not being used. Revert to keep the script simple.

Also fix whitespace in resolve-symlinks.sh.

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Move the NestJS-specific parser option to nested biome.json files in
packages/nest and workbench/nest, keeping the root config cleaner.

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
- Add @swc/core and @workflow/swc-plugin to packages/nest
- Remove @swc/cli and @swc/core from workbench/nest
- Keep @workflow/swc-plugin in workbench (required by .swcrc resolution)
- Add @workflow/nest as devDependency in workbench

The swc-plugin must remain a direct dependency in the workbench because
SWC's plugin resolution requires it to be resolvable from the project's
node_modules (referenced by name in .swcrc).

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
The SWC dependencies were added to try making them transitively available
to the workbench, but pnpm's strict isolation prevents this.

The @workflow/swc-plugin must remain a direct devDependency in the NestJS
workbench because NestJS's SWC builder reads .swcrc which references the
plugin by name - it must be resolvable from the project's node_modules.

This is different from other frameworks (Nitro, Vite, Next.js) which
integrate the workflow plugin into their build systems internally.

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
- Add @swc/core and @workflow/swc-plugin to packages/nest dependencies
- Remove @workflow/swc-plugin from workbench/nest
- Add .npmrc with public-hoist-pattern to make swc-plugin resolvable

The workbench app now only depends on @workflow/nest (like other
workbenches), and pnpm hoisting ensures the swc-plugin is available
for NestJS's SWC builder to resolve from .swcrc.

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Instead of requiring users to configure pnpm hoisting for @workflow/swc-plugin,
@workflow/nest now provides a CLI command that generates .swcrc with the
resolved plugin path. This eliminates the need for root-level .npmrc changes.

Changes:
- Add workflow-nest CLI with 'init' command that generates .swcrc
- Remove .npmrc public-hoist-pattern configuration
- Update workbench/nest to use the CLI in prebuild/predev scripts
- Add .swcrc to .gitignore (contains machine-specific absolute paths)

Users can now simply run 'npx @workflow/nest init' after installing the package.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
The workflow-nest bin command isn't available in CI because pnpm install
runs before the packages are built. Use node to run the CLI directly
from the dist folder instead.

Also add README.md to packages/nest with setup instructions and
explanation of the CLI approach.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Comment thread workbench/nest/package.json Outdated
Comment on lines +33 to +34
"@workflow/ai": "workspace:*",
"@workflow/nest": "workspace:*",
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.

I don't think these 2 are needed?
workflow/nest is already re-exporting @workflow/nest, and @worklfow/ai should not be a dev dep?

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
This reverts commit ebaf18c.
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
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.

3 participants