Skip to content

Add btoa, atob, and Buffer globals to workflow VM context#1520

Merged
pranaygp merged 2 commits into
mainfrom
v0/pranaygp-add-btoa-buffer-8667
Mar 26, 2026
Merged

Add btoa, atob, and Buffer globals to workflow VM context#1520
pranaygp merged 2 commits into
mainfrom
v0/pranaygp-add-btoa-buffer-8667

Conversation

@pranaygp
Copy link
Copy Markdown
Contributor

Enables base64 encoding and decoding inside workflow functions by exposing btoa, atob, and Buffer in the sandboxed VM context.

Requested by @Justin Sanford and @Walker Frankenberg for creating basic auth headers in workflows (stream.new migration to WDK).

What changed

  • Added g.btoa and g.atob from globalThis for Web API base64 encoding/decoding
  • Added Buffer for Node.js-style base64 operations and binary data manipulation
  • Added 5 test cases covering encoding, decoding, and the common basic auth header use case

Slack Thread

@pranaygp pranaygp requested a review from a team as a code owner March 25, 2026 20:51
Copilot AI review requested due to automatic review settings March 25, 2026 20:51
@vercel vercel Bot added the v0 label Mar 25, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 25, 2026

🦋 Changeset detected

Latest commit: 4508ed8

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 Patch
@workflow/builders Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/vitest Patch
@workflow/web-shared Patch
workflow Patch
@workflow/world-testing Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch
@workflow/ai 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 Mar 25, 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 Mar 25, 2026 9:00pm
example-nextjs-workflow-webpack Ready Ready Preview, Comment Mar 25, 2026 9:00pm
example-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-astro-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-express-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-fastify-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-hono-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-nitro-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-nuxt-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-sveltekit-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workbench-vite-workflow Ready Ready Preview, Comment Mar 25, 2026 9:00pm
workflow-docs Ready Ready Preview, Comment, Open in v0 Mar 25, 2026 9:00pm
workflow-swc-playground Ready Ready Preview, Comment Mar 25, 2026 9:00pm

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 25, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 846 0 67 913
✅ 💻 Local Development 760 0 153 913
✅ 📦 Local Production 818 0 178 996
✅ 🐘 Local Postgres 818 0 178 996
✅ 🪟 Windows 75 0 8 83
❌ 🌍 Community Worlds 131 58 24 213
✅ 📋 Other 207 0 42 249
Total 3655 58 650 4363

❌ Failed Tests

🌍 Community Worlds (58 failed)

mongodb (2 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KMKCSVHGJRBD2MPJ41MX6J10
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KMKD229QD3GTBJNH0GFBT4SW

redis (2 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KMKCSVHGJRBD2MPJ41MX6J10
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KMKD229QD3GTBJNH0GFBT4SW

turso (54 failed):

  • addTenWorkflow | wrun_01KMKCRJ0JPB3G86W89N94Y4Z7
  • addTenWorkflow | wrun_01KMKCRJ0JPB3G86W89N94Y4Z7
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KMKCSSMEFTH171A7JEV29VSH
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KMKCRTFE1F3J3FZPERYQZ71G
  • promiseRaceWorkflow | wrun_01KMKCRZ2DBXRSZ8H7JTBJTF8Z
  • promiseAnyWorkflow | wrun_01KMKCS3PWW9DMJJT3RNWCJ4NR
  • importedStepOnlyWorkflow | wrun_01KMKCT53EWES54GC8NWA68GVM
  • hookWorkflow | wrun_01KMKCSFYSEHA9TSTQ8QEB4G9J
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KMKCSVHGJRBD2MPJ41MX6J10
  • webhookWorkflow | wrun_01KMKCT4G7TTHV9ZVMXK2T1CYR
  • sleepingWorkflow | wrun_01KMKCTB9082C9FKZZ4B7D3QM5
  • parallelSleepWorkflow | wrun_01KMKCTR9EZWD8RS3TNDDDECS2
  • nullByteWorkflow | wrun_01KMKCTVPX4MF8YMG2NF0VW27Y
  • workflowAndStepMetadataWorkflow | wrun_01KMKCTY0ZXXZ45406RNDTV352
  • fetchWorkflow | wrun_01KMKCXPMHH9VSRV80V53H39AA
  • promiseRaceStressTestWorkflow | wrun_01KMKCXTP0FKPCHJ2BAS7QDPN3
  • 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_01KMKD1D42QPM2XE7N8BE6K946
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KMKD229QD3GTBJNH0GFBT4SW
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KMKD2TMYAYJXJZ5M84Z16MJH
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KMKD3F3AGKR3F878GPD2CS7E
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KMKD3R9WWZJ487T3HVW1VE1N
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KMKD3Y4KX43772CE4THXXJE8
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KMKD40FC3H2FKTQJKQMQ930D
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KMKD4GXARZ5296T8WHKQVB2A
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KMKD4PYS97T3PMZZ8PNXM23J
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KMKD4Y6NAYTEEMJF0FWTX1S8
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KMKD55J68GC31P57VDYY9SP6
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KMKD5CFKKNE0VWY0YM7PPZT7
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KMKD5KF5R69JWKCRY4MCV5SR
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KMKD5TDWDJR4F1E6FVG6FVVF
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KMKD6625QFXZD542QW3JYZGY
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KMKD6E9CNDH59KN48825H2TM
  • cancelRun - cancelling a running workflow | wrun_01KMKD6N8A21VQYKAEDTT3XZWW
  • cancelRun via CLI - cancelling a running workflow | wrun_01KMKD6YRHE54R88S14M8T49YH
  • 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_01KMKD7BJBV853KWMX16ZKS3Q3
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KMKD8084VFD7TQ4WEG7SD7Z2
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KMKD8ASR5KEQ201EK60BCMPC

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 76 0 7
✅ example 76 0 7
✅ express 76 0 7
✅ fastify 76 0 7
✅ hono 76 0 7
✅ nextjs-turbopack 81 0 2
✅ nextjs-webpack 81 0 2
✅ nitro 76 0 7
✅ nuxt 76 0 7
✅ sveltekit 76 0 7
✅ vite 76 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 69 0 14
✅ express-stable 69 0 14
✅ fastify-stable 69 0 14
✅ hono-stable 69 0 14
✅ nextjs-turbopack-canary 58 0 25
✅ nextjs-turbopack-stable 75 0 8
✅ nextjs-webpack-stable 75 0 8
✅ nitro-stable 69 0 14
✅ nuxt-stable 69 0 14
✅ sveltekit-stable 69 0 14
✅ vite-stable 69 0 14
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 69 0 14
✅ express-stable 69 0 14
✅ fastify-stable 69 0 14
✅ hono-stable 69 0 14
✅ nextjs-turbopack-canary 58 0 25
✅ nextjs-turbopack-stable 75 0 8
✅ nextjs-webpack-canary 58 0 25
✅ nextjs-webpack-stable 75 0 8
✅ nitro-stable 69 0 14
✅ nuxt-stable 69 0 14
✅ sveltekit-stable 69 0 14
✅ vite-stable 69 0 14
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 69 0 14
✅ express-stable 69 0 14
✅ fastify-stable 69 0 14
✅ hono-stable 69 0 14
✅ nextjs-turbopack-canary 58 0 25
✅ nextjs-turbopack-stable 75 0 8
✅ nextjs-webpack-canary 58 0 25
✅ nextjs-webpack-stable 75 0 8
✅ nitro-stable 69 0 14
✅ nuxt-stable 69 0 14
✅ sveltekit-stable 69 0 14
✅ vite-stable 69 0 14
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 75 0 8
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 5 0 0
❌ mongodb 56 2 8
✅ redis-dev 5 0 0
❌ redis 56 2 8
✅ turso-dev 5 0 0
❌ turso 4 54 8
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 69 0 14
✅ e2e-local-postgres-nest-stable 69 0 14
✅ e2e-local-prod-nest-stable 69 0 14

📋 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 Mar 25, 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.046s (+1.3%) 1.006s (~) 0.960s 10 1.00x
💻 Local Nitro 0.048s (+7.9% 🔺) 1.006s (~) 0.958s 10 1.05x
🐘 Postgres Nitro 0.062s (-4.6%) 1.014s (~) 0.952s 10 1.35x
🐘 Postgres Express 0.062s (+3.7%) 1.011s (~) 0.949s 10 1.37x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 0.461s (-22.3% 🟢) 2.211s (-5.7% 🟢) 1.750s 10 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Nitro 1.133s (+0.5%) 2.006s (~) 0.873s 10 1.00x
💻 Local Express 1.137s (~) 2.006s (~) 0.869s 10 1.00x
🐘 Postgres Nitro 1.142s (~) 2.010s (~) 0.868s 10 1.01x
🐘 Postgres Express 1.145s (~) 2.012s (~) 0.867s 10 1.01x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.109s (-9.0% 🟢) 3.414s (-8.4% 🟢) 1.305s 10 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 10.889s (~) 11.020s (~) 0.132s 3 1.00x
🐘 Postgres Nitro 10.907s (~) 11.355s (+3.0%) 0.449s 3 1.00x
💻 Local Express 10.921s (~) 11.023s (~) 0.103s 3 1.00x
💻 Local Nitro 10.958s (~) 11.024s (~) 0.066s 3 1.01x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 16.942s (-12.0% 🟢) 18.538s (-9.6% 🟢) 1.596s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 14.408s (-0.6%) 15.025s (~) 0.617s 4 1.00x
🐘 Postgres Express 14.538s (~) 15.023s (~) 0.485s 4 1.01x
💻 Local Express 14.950s (~) 15.030s (-3.2%) 0.080s 4 1.04x
💻 Local Nitro 15.009s (~) 15.279s (~) 0.270s 4 1.04x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 34.105s (+0.6%) 35.525s (+1.3%) 1.420s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 13.671s (-2.3%) 14.022s (-3.0%) 0.351s 7 1.00x
🐘 Postgres Express 13.857s (-0.6%) 14.026s (-3.0%) 0.168s 7 1.01x
💻 Local Express 16.506s (-0.9%) 17.030s (~) 0.525s 6 1.21x
💻 Local Nitro 16.645s (~) 17.031s (~) 0.387s 6 1.22x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 55.236s (-6.7% 🟢) 57.075s (-5.7% 🟢) 1.840s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.242s (-1.0%) 2.009s (~) 0.767s 15 1.00x
🐘 Postgres Express 1.268s (~) 2.010s (~) 0.742s 15 1.02x
💻 Local Express 1.505s (-2.8%) 2.006s (~) 0.501s 15 1.21x
💻 Local Nitro 1.507s (~) 2.006s (~) 0.499s 15 1.21x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.335s (+2.4%) 3.633s (+2.2%) 1.298s 9 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 2.323s (~) 3.009s (~) 0.686s 10 1.00x
🐘 Postgres Express 2.341s (~) 3.012s (~) 0.671s 10 1.01x
💻 Local Nitro 2.896s (-0.7%) 3.208s (+3.2%) 0.313s 10 1.25x
💻 Local Express 2.959s (~) 3.309s (-1.0%) 0.350s 10 1.27x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.611s (-9.5% 🟢) 3.787s (-10.4% 🟢) 1.177s 8 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 3.460s (-0.6%) 4.012s (~) 0.552s 8 1.00x
🐘 Postgres Express 3.500s (+1.1%) 4.014s (~) 0.514s 8 1.01x
💻 Local Nitro 7.651s (-9.0% 🟢) 8.020s (-11.1% 🟢) 0.370s 4 2.21x
💻 Local Express 8.211s (+8.5% 🔺) 9.019s (+9.0% 🔺) 0.808s 4 2.37x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.488s (+7.6% 🔺) 5.124s (+12.7% 🔺) 1.636s 7 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.239s (-1.4%) 2.010s (~) 0.770s 15 1.00x
🐘 Postgres Express 1.257s (~) 2.009s (~) 0.752s 15 1.01x
💻 Local Nitro 1.512s (-3.2%) 2.006s (~) 0.493s 15 1.22x
💻 Local Express 1.569s (+2.5%) 2.073s (+3.4%) 0.504s 15 1.27x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.102s (-13.5% 🟢) 3.349s (-8.9% 🟢) 1.247s 9 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 2.308s (~) 3.011s (~) 0.704s 10 1.00x
🐘 Postgres Express 2.348s (+0.7%) 3.010s (~) 0.662s 10 1.02x
💻 Local Nitro 2.886s (-8.3% 🟢) 3.208s (-17.4% 🟢) 0.322s 10 1.25x
💻 Local Express 3.213s (+5.7% 🔺) 4.010s (+12.4% 🔺) 0.796s 8 1.39x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.863s (-5.9% 🟢) 3.959s (-8.8% 🟢) 1.097s 8 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 3.451s (~) 4.011s (~) 0.560s 8 1.00x
🐘 Postgres Express 3.472s (~) 4.012s (~) 0.540s 8 1.01x
💻 Local Nitro 8.342s (-6.0% 🟢) 9.021s (-2.7%) 0.679s 4 2.42x
💻 Local Express 8.926s (+3.3%) 9.270s (+2.8%) 0.344s 4 2.59x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.763s (+6.0% 🔺) 5.339s (+7.0% 🔺) 1.575s 6 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.750s (-6.6% 🟢) 1.006s (~) 0.256s 60 1.00x
🐘 Postgres Express 0.815s (+1.7%) 1.006s (~) 0.191s 60 1.09x
💻 Local Express 0.983s (~) 1.205s (+6.0% 🔺) 0.222s 50 1.31x
💻 Local Nitro 1.020s (+5.0% 🔺) 1.771s (+70.4% 🔺) 0.751s 34 1.36x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 9.549s (-4.8%) 10.955s (-4.1%) 1.407s 6 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 1.776s (-8.5% 🟢) 2.008s (-9.9% 🟢) 0.232s 45 1.00x
🐘 Postgres Express 1.916s (~) 2.052s (~) 0.137s 45 1.08x
💻 Local Express 2.969s (-1.5%) 3.180s (-10.4% 🟢) 0.211s 29 1.67x
💻 Local Nitro 3.067s (+2.1%) 3.843s (+8.3% 🔺) 0.775s 24 1.73x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 29.551s (-9.3% 🟢) 30.745s (-9.0% 🟢) 1.194s 3 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 3.629s (-6.5% 🟢) 4.011s (-2.4%) 0.382s 30 1.00x
🐘 Postgres Express 3.987s (+0.5%) 4.404s (+2.8%) 0.418s 28 1.10x
💻 Local Express 9.058s (-1.2%) 9.710s (-1.6%) 0.652s 13 2.50x
💻 Local Nitro 9.084s (~) 9.710s (~) 0.626s 13 2.50x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 100.517s (+17.8% 🔺) 101.818s (+17.3% 🔺) 1.301s 2 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.261s (-4.2%) 1.008s (~) 0.746s 60 1.00x
🐘 Postgres Express 0.298s (+3.8%) 1.008s (~) 0.710s 60 1.14x
💻 Local Nitro 0.574s (-6.3% 🟢) 1.004s (~) 0.431s 60 2.20x
💻 Local Express 0.595s (~) 1.004s (~) 0.409s 60 2.28x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 1.907s (+20.2% 🔺) 3.582s (+9.3% 🔺) 1.675s 17 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.473s (-4.6%) 1.007s (~) 0.534s 90 1.00x
🐘 Postgres Express 0.507s (~) 1.008s (~) 0.501s 90 1.07x
💻 Local Nitro 2.504s (-1.1%) 3.009s (~) 0.505s 30 5.30x
💻 Local Express 2.554s (+1.3%) 3.008s (~) 0.454s 30 5.40x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 3.714s (+7.1% 🔺) 5.052s (+1.0%) 1.338s 19 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: Next.js (Turbopack)

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.717s (-5.9% 🟢) 1.007s (~) 0.290s 120 1.00x
🐘 Postgres Express 0.797s (+1.9%) 1.009s (~) 0.212s 119 1.11x
💻 Local Nitro 10.759s (-4.3%) 11.210s (-6.8% 🟢) 0.451s 11 15.01x
💻 Local Express 11.343s (+1.8%) 11.846s (~) 0.503s 11 15.83x
💻 Local Next.js (Turbopack) ⚠️ missing - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - -

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 6.777s (-4.8%) 8.165s (-3.0%) 1.387s 15 1.00x
▲ Vercel Express ⚠️ missing - - - -
▲ Vercel Nitro ⚠️ missing - - - -

🔍 Observability: 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
🐘 Postgres 🥇 Nitro 0.188s (-5.9% 🟢) 0.993s (-0.5%) 0.001s (~) 1.011s (~) 0.823s 10 1.00x
🐘 Postgres Express 0.200s (-2.8%) 0.993s (~) 0.001s (-7.7% 🟢) 1.010s (~) 0.809s 10 1.06x
💻 Local Express 0.203s (-2.5%) 1.003s (~) 0.011s (-1.7%) 1.018s (~) 0.815s 10 1.08x
💻 Local Nitro 0.221s (+8.5% 🔺) 1.003s (~) 0.010s (-12.6% 🟢) 1.017s (~) 0.796s 10 1.17x
💻 Local Next.js (Turbopack) ⚠️ missing - - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 1.813s (+9.3% 🔺) 2.909s (+2.4%) 0.400s (-26.4% 🟢) 3.820s (-2.0%) 2.007s 10 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: 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.563s (-6.0% 🟢) 1.002s (~) 0.005s (+29.1% 🔺) 1.024s (~) 0.461s 59 1.00x
🐘 Postgres Express 0.593s (-3.7%) 1.004s (~) 0.004s (+7.5% 🔺) 1.024s (~) 0.431s 59 1.05x
💻 Local Express 0.731s (-0.8%) 1.009s (~) 0.010s (+5.1% 🔺) 1.024s (~) 0.293s 59 1.30x
💻 Local Nitro 0.757s (+4.3%) 1.009s (~) 0.008s (-24.4% 🟢) 1.021s (~) 0.264s 59 1.34x
💻 Local Next.js (Turbopack) ⚠️ missing - - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 5.688s (+32.2% 🔺) 6.733s (+25.2% 🔺) 0.288s (+7.8% 🔺) 7.719s (+24.9% 🔺) 2.032s 8 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Next.js (Turbopack)

10 parallel streams (1MB each)

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 0.911s (-4.4%) 1.082s (-13.0% 🟢) 0.000s (-100.0% 🟢) 1.112s (-11.7% 🟢) 0.201s 55 1.00x
🐘 Postgres Express 0.970s (+1.3%) 1.185s (-2.2%) 0.000s (-2.0%) 1.211s (-1.5%) 0.241s 51 1.06x
💻 Local Nitro 1.227s (-1.0%) 2.020s (~) 0.000s (-36.4% 🟢) 2.023s (~) 0.797s 30 1.35x
💻 Local Express 1.244s (-0.5%) 2.021s (~) 0.000s (+120.0% 🔺) 2.024s (~) 0.780s 30 1.37x
💻 Local Next.js (Turbopack) ⚠️ missing - - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 24.880s (+671.0% 🔺) 25.725s (+514.6% 🔺) 0.000s (-100.0% 🟢) 26.234s (+459.4% 🔺) 1.354s 9 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: 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.648s (-5.7% 🟢) 2.096s (-1.9%) 0.000s (-100.0% 🟢) 2.114s (-1.6%) 0.466s 29 1.00x
🐘 Postgres Express 1.790s (+1.2%) 2.133s (+1.7%) 0.000s (NaN%) 2.148s (~) 0.358s 29 1.09x
💻 Local Nitro 3.389s (-2.7%) 4.032s (-1.6%) 0.001s (+66.7% 🔺) 4.037s (-1.6%) 0.647s 15 2.06x
💻 Local Express 3.521s (+2.2%) 4.031s (~) 0.001s (-33.3% 🟢) 4.036s (~) 0.515s 15 2.14x
💻 Local Next.js (Turbopack) ⚠️ missing - - - - -
🐘 Postgres Next.js (Turbopack) ⚠️ missing - - - - -

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 4.899s (+22.9% 🔺) 5.762s (+21.2% 🔺) 0.000s (+Infinity% 🔺) 6.319s (+19.7% 🔺) 1.421s 10 1.00x
▲ Vercel Express ⚠️ missing - - - - -
▲ Vercel Nitro ⚠️ missing - - - - -

🔍 Observability: Next.js (Turbopack)

Summary

Fastest Framework by World

Winner determined by most benchmark wins

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

Winner determined by most benchmark wins

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


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

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

Exposes base64 helpers (atob, btoa) and Node’s Buffer in the workflow VM sandbox so workflow code can build/parse base64 payloads (e.g., Basic Auth headers) while running under packages/core’s deterministic VM context.

Changes:

  • Add g.atob/g.btoa bindings to the VM context globals.
  • Add Buffer to the VM context globals for Node-style base64 and binary manipulation.
  • Add new unit tests validating base64 encode/decode and Basic Auth-style usage.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
packages/core/src/vm/index.ts Exposes atob, btoa, and Buffer in the sandboxed vm.Context.
packages/core/src/vm/index.test.ts Adds tests covering atob/btoa/Buffer base64 behavior and a Basic Auth-style scenario.

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

Comment on lines +103 to +104
// Node.js Buffer for base64 encoding/decoding and binary data manipulation
(g as any).Buffer = Buffer;
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

Exposing the full Node Buffer into the deterministic sandbox allows Buffer.allocUnsafe(...) / Buffer(...) / new Buffer(...), which can return uninitialized memory. That is both a potential data-leak vector and a source of non-determinism (buffer contents depend on process heap state), undermining the goal of createContext.

Consider exposing a "safe" Buffer wrapper/proxy that (a) routes numeric allocations through Buffer.alloc (zero-filled), (b) disables/overrides allocUnsafe/allocUnsafeSlow, and ideally (c) throws on deprecated Buffer(number) usage. Add a small test asserting unsafe allocation paths are not available or are deterministic (zero-filled).

Suggested change
// Node.js Buffer for base64 encoding/decoding and binary data manipulation
(g as any).Buffer = Buffer;
// Node.js Buffer for base64 encoding/decoding and binary data manipulation.
// Expose a "safe" Buffer wrapper to keep the sandbox deterministic and avoid
// uninitialized memory via allocUnsafe / deprecated numeric constructors.
const SafeBuffer: typeof Buffer = new Proxy(Buffer, {
// Handle direct calls like Buffer(...)
apply(target, thisArg, argArray: any[]) {
const [arg0, ...rest] = argArray;
if (typeof arg0 === 'number') {
// Route numeric constructor usage to zero-filled allocation
return Buffer.alloc(arg0);
}
return Reflect.apply(target as any, thisArg, argArray);
},
// Handle construction like new Buffer(...)
construct(target, argArray: any[], newTarget) {
const [arg0, ...rest] = argArray;
if (typeof arg0 === 'number') {
// Route numeric constructor usage to zero-filled allocation
return Buffer.alloc(arg0);
}
return Reflect.construct(target as any, argArray, newTarget);
},
get(target, prop, receiver) {
if (prop === 'allocUnsafe' || prop === 'allocUnsafeSlow') {
// Disable unsafe allocation paths inside the deterministic sandbox
return function () {
throw new Error('Buffer allocUnsafe methods are disabled in this sandbox');
};
}
return Reflect.get(target as any, prop, receiver);
},
});
(g as any).Buffer = SafeBuffer;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

overkill for now but worth reconsidering in a future update

@vercel vercel Bot force-pushed the v0/pranaygp-add-btoa-buffer-8667 branch from ea67eec to 4508ed8 Compare March 25, 2026 20:58
@pranaygp pranaygp enabled auto-merge (squash) March 25, 2026 21:00
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.

LGTM. Copilot might have a point about preventing allocUnsafe, though I personally can't tell. I think you could do a follow-up query to validate that

@pranaygp pranaygp disabled auto-merge March 26, 2026 00:34
@pranaygp pranaygp merged commit 8e7083b into main Mar 26, 2026
101 of 105 checks passed
@pranaygp pranaygp deleted the v0/pranaygp-add-btoa-buffer-8667 branch March 26, 2026 00:34
@ghost ghost mentioned this pull request Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants