Skip to content

Fix projectConfig.projectId containing project name instead of ID#999

Merged
TooTallNate merged 3 commits intomainfrom
nate/fix-project-config
Feb 18, 2026
Merged

Fix projectConfig.projectId containing project name instead of ID#999
TooTallNate merged 3 commits intomainfrom
nate/fix-project-config

Conversation

@TooTallNate
Copy link
Copy Markdown
Member

@TooTallNate TooTallNate commented Feb 11, 2026

Summary

  • Fixes WORKFLOW_VERCEL_PROJECT env var to contain the real project ID instead of the project name/slug
  • Adds WORKFLOW_VERCEL_PROJECT_NAME for the project slug

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 11, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 534 0 38 572
✅ 💻 Local Development 556 0 68 624
✅ 📦 Local Production 556 0 68 624
✅ 🐘 Local Postgres 556 0 68 624
✅ 🪟 Windows 49 0 3 52
❌ 🌍 Community Worlds 111 45 9 165
✅ 📋 Other 135 0 21 156
Total 2497 45 275 2817

❌ Failed Tests

🌍 Community Worlds (45 failed)

turso (45 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • parallelSleepWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • 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 retry behavior workflow completes despite transient 5xx on step_completed
  • 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 (queue-based) - workflow and step endpoints respond to health check messages
  • 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
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • cancelRun - cancelling a running workflow
  • cancelRun via CLI - cancelling a running workflow
  • 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 48 0 4
✅ example 48 0 4
✅ express 48 0 4
✅ fastify 48 0 4
✅ hono 48 0 4
✅ nextjs-turbopack 51 0 1
✅ nextjs-webpack 51 0 1
✅ nitro 48 0 4
✅ nuxt 48 0 4
✅ sveltekit 48 0 4
✅ vite 48 0 4
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 45 0 7
✅ express-stable 45 0 7
✅ fastify-stable 45 0 7
✅ hono-stable 45 0 7
✅ nextjs-turbopack-canary 49 0 3
✅ nextjs-turbopack-stable 49 0 3
✅ nextjs-webpack-canary 49 0 3
✅ nextjs-webpack-stable 49 0 3
✅ nitro-stable 45 0 7
✅ nuxt-stable 45 0 7
✅ sveltekit-stable 45 0 7
✅ vite-stable 45 0 7
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 45 0 7
✅ express-stable 45 0 7
✅ fastify-stable 45 0 7
✅ hono-stable 45 0 7
✅ nextjs-turbopack-canary 49 0 3
✅ nextjs-turbopack-stable 49 0 3
✅ nextjs-webpack-canary 49 0 3
✅ nextjs-webpack-stable 49 0 3
✅ nitro-stable 45 0 7
✅ nuxt-stable 45 0 7
✅ sveltekit-stable 45 0 7
✅ vite-stable 45 0 7
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 45 0 7
✅ express-stable 45 0 7
✅ fastify-stable 45 0 7
✅ hono-stable 45 0 7
✅ nextjs-turbopack-canary 49 0 3
✅ nextjs-turbopack-stable 49 0 3
✅ nextjs-webpack-canary 49 0 3
✅ nextjs-webpack-stable 49 0 3
✅ nitro-stable 45 0 7
✅ nuxt-stable 45 0 7
✅ sveltekit-stable 45 0 7
✅ vite-stable 45 0 7
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 49 0 3
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 0
✅ mongodb 49 0 3
✅ redis-dev 3 0 0
✅ redis 49 0 3
✅ turso-dev 3 0 0
❌ turso 4 45 3
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 45 0 7
✅ e2e-local-postgres-nest-stable 45 0 7
✅ e2e-local-prod-nest-stable 45 0 7

📋 View full workflow run

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 11, 2026

🦋 Changeset detected

Latest commit: 2a6cf4b

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

This PR includes changesets to release 16 packages
Name Type
@workflow/cli Patch
@workflow/core Patch
@workflow/web Patch
@workflow/world-vercel Patch
workflow Patch
@workflow/world-testing Patch
@workflow/builders Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/web-shared Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Feb 11, 2026

@TooTallNate TooTallNate marked this pull request as ready for review February 11, 2026 04:18
Copilot AI review requested due to automatic review settings February 11, 2026 04:18
Copy link
Copy Markdown
Contributor

@vercel vercel Bot left a comment

Choose a reason for hiding this comment

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

Additional Suggestion:

Connection status UI displays opaque Vercel project ID (e.g., prj_xxx) instead of the human-readable project name after WORKFLOW_VERCEL_PROJECT was changed to store the real project ID.

Fix on Vercel

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

This PR fixes inconsistent handling of Vercel project identity by separating the project ID (used for API/auth/encryption contexts) from the project slug/name (used for dashboard URLs and display), and wires the new env var through CLI, core runtime, and the web server’s Vercel world creation path.

Changes:

  • Added WORKFLOW_VERCEL_PROJECT_NAME (project slug/name) alongside WORKFLOW_VERCEL_PROJECT (real prj_… id).
  • Updated CLI env inference to set WORKFLOW_VERCEL_PROJECT to the true project ID and populate the new project-name env var.
  • Plumbed projectName through core/runtime world creation and web server env allowlists / Vercel world instantiation.

Reviewed changes

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

Show a summary per file
File Description
packages/world-vercel/src/utils.ts Extends Vercel world config typing to include both project ID and project slug/name.
packages/web/src/server/workflow-server-actions.ts Allows the new env var to reach the client and passes it into createVercelWorld().
packages/core/src/runtime/world.ts Adds WORKFLOW_VERCEL_PROJECT_NAME into the runtime’s Vercel world config.
packages/cli/src/lib/inspect/web.ts Uses project slug/name (when available) for dashboard URL generation.
packages/cli/src/lib/inspect/env.ts Adds the new env var and updates Vercel env inference to distinguish ID vs name.

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

Comment on lines 203 to +207
'WORKFLOW_TARGET_WORLD',
'WORKFLOW_VERCEL_ENV',
'WORKFLOW_VERCEL_TEAM',
'WORKFLOW_VERCEL_PROJECT',
'WORKFLOW_VERCEL_PROJECT_NAME',
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

PR description says the web UI was updated to prefer the Vercel project name/slug when available, but the only consumer updated here appears to be the CLI dashboard URL logic. The web UI still appears to read/display WORKFLOW_VERCEL_PROJECT (now intended to be the prj_… id), so the UI may show IDs instead of friendly slugs unless the client-side components are updated to use WORKFLOW_VERCEL_PROJECT_NAME.

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

Choose a reason for hiding this comment

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

The web UI path changed significantly during the React Router refactor. The web server actions now use createVercelWorld() which receives projectConfig with both projectId and projectName. The dashboard URL logic uses the name/slug.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The web server actions use createVercelWorld() which receives both projectId and projectName via projectConfig. The dashboard URL uses the name/slug. No additional web UI changes needed.

Comment on lines +193 to +196
// WORKFLOW_VERCEL_PROJECT is the real project ID (e.g., prj_xxx)
envVars.WORKFLOW_VERCEL_PROJECT = projectId;
// WORKFLOW_VERCEL_PROJECT_NAME is the project slug (e.g., my-app)
envVars.WORKFLOW_VERCEL_PROJECT_NAME = projectName || projectId;
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

inferVercelEnvVars() only populates WORKFLOW_VERCEL_PROJECT_NAME (and normalizes WORKFLOW_VERCEL_PROJECT to a real prj_… id) when either WORKFLOW_VERCEL_PROJECT or WORKFLOW_VERCEL_TEAM is missing. If the CLI flag/env already sets WORKFLOW_VERCEL_PROJECT to a project slug/name (which the --project flag description currently implies), this block won’t run, and the world will continue sending the slug in the x-vercel-project-id header—reintroducing the exact bug this PR is fixing and potentially breaking auth/encryption context. Consider expanding the guard to also run when WORKFLOW_VERCEL_PROJECT_NAME is missing and/or when WORKFLOW_VERCEL_PROJECT doesn’t look like a Vercel project id (e.g. not prj_…), so the env vars are consistently normalized.

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

Choose a reason for hiding this comment

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

The inference logic normalizes the env var to a real project ID when the linked project is available. If the user sets WORKFLOW_VERCEL_PROJECT to a slug, the inference step replaces it with the real ID from .vercel/project.json.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed — the guard now also runs when WORKFLOW_VERCEL_PROJECT does not start with prj_ or when WORKFLOW_VERCEL_PROJECT_NAME is missing, ensuring consistent normalization regardless of how the env vars were initially populated.

@TooTallNate TooTallNate force-pushed the nate/fix-project-config branch from a4be5e8 to 53d573e Compare February 11, 2026 05:23
@TooTallNate TooTallNate force-pushed the nate/encryptor-interface branch from 30fc9e5 to fc25b9c Compare February 11, 2026 05:23
@TooTallNate TooTallNate force-pushed the nate/fix-project-config branch from 2746c5a to c6af179 Compare February 16, 2026 07:56
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 but comment is changelog is off

Comment thread .changeset/fix-project-config.md Outdated
"@workflow/world-vercel": patch
---

Fix `projectConfig.projectId` to contain the real project ID instead of the project name
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems off. The actual code doesn't change projectId at all. It seems more like:

Suggested change
Fix `projectConfig.projectId` to contain the real project ID instead of the project name
In UI, show project name instead in ID when available

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No it's not a UI change. In the world-vercel projectConfig, the projectId was previously being set to the project slug, not the ID.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated the changeset description to: "Separate project ID and project name into distinct env vars (WORKFLOW_VERCEL_PROJECT and WORKFLOW_VERCEL_PROJECT_NAME)"

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.

Overall this is a clean and well-scoped fix. The separation of project ID vs project name/slug is the right approach. Two items to address:

  1. Connection status UI regression: packages/web/app/components/display-utils/connection-status.tsx:33 reads publicEnv.WORKFLOW_VERCEL_PROJECT to display the connection info string (e.g. team/project). Since WORKFLOW_VERCEL_PROJECT now contains the opaque prj_xxx ID, this will show IDs instead of friendly names. Should be updated to prefer WORKFLOW_VERCEL_PROJECT_NAME, same pattern as packages/cli/src/lib/inspect/web.ts:101-102:
const project = publicEnv.WORKFLOW_VERCEL_PROJECT_NAME || publicEnv.WORKFLOW_VERCEL_PROJECT;

The Vercel bot flagged this as well.

  1. Changeset description is misleading (see inline comment).

Comment thread .changeset/fix-project-config.md Outdated
"@workflow/world-vercel": patch
---

Fix `projectConfig.projectId` to contain the real project ID instead of the project name
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.

Agree with @VaguelySerious — the changeset description is misleading. The PR doesn't change what projectConfig.projectId contains (it was always the real project ID from .vercel/project.json). The actual fix is that WORKFLOW_VERCEL_PROJECT env var now correctly stores the real project ID instead of the project name/slug, and a new WORKFLOW_VERCEL_PROJECT_NAME env var is introduced for the slug.

Suggested:

Separate project ID and project name into distinct env vars (WORKFLOW_VERCEL_PROJECT and WORKFLOW_VERCEL_PROJECT_NAME)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed — used your suggested wording.

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.

Did a broader pass across the codebase for project ID/name consistency. A few more things beyond my earlier review:

Naming inconsistency: WORKFLOW_VERCEL_PROJECT_SLUG vs WORKFLOW_VERCEL_PROJECT_NAME

CI already defines a third env var — WORKFLOW_VERCEL_PROJECT_SLUG — used in tests.yml:268, benchmarks.yml:397, and consumed by e2e tests (packages/core/e2e/e2e.test.ts:62) and benchmarks (packages/core/e2e/bench.bench.ts:156). This PR introduces WORKFLOW_VERCEL_PROJECT_NAME for the same concept. That's now two env vars for the project slug/name. Worth unifying on one name (probably WORKFLOW_VERCEL_PROJECT_NAME since it's the new standard) and updating CI + e2e tests to match, or at minimum documenting the relationship.

--project CLI flag can accept a slug

In packages/cli/src/lib/inspect/flags.ts:52-61, the --project flag maps directly to WORKFLOW_VERCEL_PROJECT. Its description says "the vercel project to authenticate against" — users could reasonably pass a slug here. In setup.ts:78, this value is written straight to WORKFLOW_VERCEL_PROJECT before inferVercelEnvVars() runs. Since inferVercelEnvVars() only triggers when WORKFLOW_VERCEL_PROJECT is empty (line 188), a user-provided slug would persist as the "project ID" and get sent in the x-vercel-project-id header — reintroducing the original bug. This is the same concern Copilot raised. Consider either:

  • Normalizing in inferVercelEnvVars even when the env var is already set (e.g., if it doesn't start with prj_)
  • Or splitting the flag into --project-id and --project-name

projectName is carried but never consumed in world-vercel

The APIConfig.projectConfig.projectName field was added to the type in packages/world-vercel/src/utils.ts:40, but getHeaders() (line 173) and getHttpUrl() (line 155) never read it — only projectId and teamId are used for headers and proxy routing. This is fine since it's only for display, but a doc note clarifying it's not sent to the server would help future readers.

// WORKFLOW_VERCEL_PROJECT is the real project ID (e.g., prj_xxx)
envVars.WORKFLOW_VERCEL_PROJECT = projectId;
// WORKFLOW_VERCEL_PROJECT_NAME is the project slug (e.g., my-app)
envVars.WORKFLOW_VERCEL_PROJECT_NAME = projectName || projectId;
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 guard on line 188 (!envVars.WORKFLOW_VERCEL_PROJECT || !envVars.WORKFLOW_VERCEL_TEAM) means inference is skipped entirely when both are already set. But WORKFLOW_VERCEL_PROJECT could contain a slug from the --project CLI flag (see flags.ts:58 and setup.ts:78), and WORKFLOW_VERCEL_PROJECT_NAME would remain empty.

Consider also running normalization when WORKFLOW_VERCEL_PROJECT is set but doesn't look like a real project ID (e.g., doesn't start with prj_), or when WORKFLOW_VERCEL_PROJECT_NAME is missing. This would make the env vars robust regardless of how they were initially populated.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch. Expanded the guard to also run inference when:

  • WORKFLOW_VERCEL_PROJECT does not start with prj_ (e.g., slug from --project flag)
  • WORKFLOW_VERCEL_PROJECT_NAME is missing

Also changed the team assignment to preserve an explicitly set team (envVars.WORKFLOW_VERCEL_TEAM || teamId) so only missing values get populated during normalization.

Comment thread packages/core/src/runtime/world.ts Outdated
projectConfig: {
environment: process.env.WORKFLOW_VERCEL_ENV,
projectId: process.env.WORKFLOW_VERCEL_PROJECT,
projectName: process.env.WORKFLOW_VERCEL_PROJECT_NAME,
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.

nit: Could add a brief comment here (like in env.ts) clarifying the distinction:

projectId: process.env.WORKFLOW_VERCEL_PROJECT,      // real ID (prj_xxx)
projectName: process.env.WORKFLOW_VERCEL_PROJECT_NAME, // slug (my-app)

Helps future readers understand the split without needing to trace back to the CLI.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added inline comments clarifying the distinction.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 18, 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.032s (+1.6%) 1.005s (~) 0.973s 10 1.00x
💻 Local Nitro 0.034s (+1.2%) 1.005s (~) 0.971s 10 1.05x
🌐 Redis Next.js (Turbopack) 0.038s 1.005s 0.967s 10 1.18x
💻 Local Next.js (Turbopack) 0.043s 1.004s 0.961s 10 1.33x
🌐 MongoDB Next.js (Turbopack) 0.100s 1.007s 0.907s 10 3.10x
🐘 Postgres Nitro 0.106s (-45.6% 🟢) 1.010s (~) 0.904s 10 3.26x
🐘 Postgres Express 0.134s (-71.5% 🟢) 1.010s (-0.5%) 0.876s 10 4.14x
🐘 Postgres Next.js (Turbopack) 0.453s 1.009s 0.557s 10 13.97x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 0.513s (-13.6% 🟢) 1.784s (-21.4% 🟢) 1.271s 10 1.00x
▲ Vercel Nitro 0.684s (-1.0%) 2.144s (+2.6%) 1.460s 10 1.33x
▲ Vercel Next.js (Turbopack) 0.979s (+34.7% 🔺) 2.389s (+2.1%) 1.410s 10 1.91x

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

workflow with 1 step

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 1.089s 2.006s 0.918s 10 1.00x
💻 Local Next.js (Turbopack) 1.095s 2.005s 0.910s 10 1.01x
💻 Local Express 1.105s (~) 2.006s (~) 0.900s 10 1.02x
💻 Local Nitro 1.112s (~) 2.005s (~) 0.893s 10 1.02x
🌐 MongoDB Next.js (Turbopack) 1.309s 2.009s 0.700s 10 1.20x
🐘 Postgres Next.js (Turbopack) 1.841s 2.011s 0.171s 10 1.69x
🐘 Postgres Express 2.456s (+3.2%) 3.014s (~) 0.558s 10 2.26x
🐘 Postgres Nitro 2.495s (+18.5% 🔺) 3.013s (+3.4%) 0.518s 10 2.29x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.226s (-2.3%) 3.401s (-4.2%) 1.175s 10 1.00x
▲ Vercel Next.js (Turbopack) 2.332s (+5.3% 🔺) 3.767s (+7.6% 🔺) 1.435s 10 1.05x
▲ Vercel Nitro 2.802s (+22.8% 🔺) 4.038s (+28.6% 🔺) 1.236s 10 1.26x

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

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 10.594s 11.022s 0.429s 3 1.00x
💻 Local Next.js (Turbopack) 10.697s 11.020s 0.323s 3 1.01x
💻 Local Express 10.819s (~) 11.023s (~) 0.203s 3 1.02x
💻 Local Nitro 10.887s (~) 11.024s (~) 0.137s 3 1.03x
🌐 MongoDB Next.js (Turbopack) 12.341s 13.022s 0.680s 3 1.16x
🐘 Postgres Next.js (Turbopack) 15.273s 16.043s 0.771s 2 1.44x
🐘 Postgres Express 20.327s (~) 21.059s (~) 0.732s 2 1.92x
🐘 Postgres Nitro 20.388s (+32.0% 🔺) 21.054s (+31.2% 🔺) 0.666s 2 1.92x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 17.270s (+0.9%) 18.449s (+3.7%) 1.179s 2 1.00x
▲ Vercel Next.js (Turbopack) 17.501s (-2.8%) 18.877s (-1.6%) 1.376s 2 1.01x
▲ Vercel Nitro 18.538s (+5.0% 🔺) 19.543s (+5.2% 🔺) 1.005s 2 1.07x

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

workflow with 25 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 26.563s 27.051s 0.488s 3 1.00x
💻 Local Next.js (Turbopack) 27.133s 28.048s 0.915s 3 1.02x
💻 Local Express 27.473s (~) 28.050s (~) 0.577s 3 1.03x
💻 Local Nitro 27.607s (~) 28.053s (~) 0.446s 3 1.04x
🌐 MongoDB Next.js (Turbopack) 30.649s 31.045s 0.396s 2 1.15x
🐘 Postgres Next.js (Turbopack) 37.630s 38.089s 0.459s 2 1.42x
🐘 Postgres Nitro 50.155s (+32.8% 🔺) 50.622s (+32.9% 🔺) 0.467s 2 1.89x
🐘 Postgres Express 50.347s (~) 51.133s (~) 0.785s 2 1.90x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 43.009s (-4.6%) 45.845s (-2.6%) 2.836s 2 1.00x
▲ Vercel Next.js (Turbopack) 43.117s (-4.7%) 44.092s (-4.4%) 0.974s 2 1.00x
▲ Vercel Nitro 43.536s (+3.7%) 45.021s (+3.7%) 1.485s 2 1.01x

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

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 53.737s 54.099s 0.362s 2 1.00x
💻 Local Next.js (Turbopack) 56.586s 57.096s 0.511s 2 1.05x
💻 Local Express 57.392s (~) 58.101s (~) 0.709s 2 1.07x
💻 Local Nitro 57.471s (~) 58.104s (~) 0.632s 2 1.07x
🌐 MongoDB Next.js (Turbopack) 61.136s 61.582s 0.446s 2 1.14x
🐘 Postgres Express 75.430s (-24.7% 🟢) 76.181s (-24.0% 🟢) 0.750s 2 1.40x
🐘 Postgres Next.js (Turbopack) 75.573s 76.172s 0.599s 2 1.41x
🐘 Postgres Nitro 77.254s (+2.4%) 77.669s (+1.9%) 0.415s 2 1.44x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 86.156s (~) 87.467s (~) 1.311s 2 1.00x
▲ Vercel Next.js (Turbopack) 87.287s (-1.0%) 88.401s (-1.0%) 1.113s 2 1.01x
▲ Vercel Express 92.167s (+6.0% 🔺) 92.965s (+5.8% 🔺) 0.798s 1 1.07x

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

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 1.209s 2.006s 0.797s 15 1.00x
💻 Local Next.js (Turbopack) 1.377s 2.004s 0.627s 15 1.14x
💻 Local Nitro 1.406s (-2.3%) 2.006s (~) 0.599s 15 1.16x
💻 Local Express 1.412s (~) 2.005s (~) 0.593s 15 1.17x
🐘 Postgres Next.js (Turbopack) 1.929s 2.226s 0.297s 14 1.59x
🐘 Postgres Express 2.002s (-11.5% 🟢) 2.682s (-11.0% 🟢) 0.681s 12 1.66x
🌐 MongoDB Next.js (Turbopack) 2.158s 3.008s 0.851s 10 1.78x
🐘 Postgres Nitro 2.276s (+6.7% 🔺) 3.015s (+10.0% 🔺) 0.738s 10 1.88x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.395s (-0.7%) 3.370s (-3.1%) 0.974s 9 1.00x
▲ Vercel Nitro 2.424s (-1.3%) 3.783s (+7.5% 🔺) 1.359s 8 1.01x
▲ Vercel Next.js (Turbopack) 2.836s (+11.2% 🔺) 3.768s (-1.6%) 0.932s 8 1.18x

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

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 2.403s 3.008s 0.605s 10 1.00x
💻 Local Nitro 2.526s (-3.2%) 3.008s (~) 0.481s 10 1.05x
💻 Local Next.js (Turbopack) 2.541s 3.007s 0.466s 10 1.06x
💻 Local Express 2.581s (-1.1%) 3.006s (~) 0.425s 10 1.07x
🌐 MongoDB Next.js (Turbopack) 4.693s 5.178s 0.485s 6 1.95x
🐘 Postgres Nitro 6.872s (-35.7% 🟢) 7.226s (-34.5% 🟢) 0.354s 5 2.86x
🐘 Postgres Express 10.043s (+7.1% 🔺) 10.367s (+8.7% 🔺) 0.323s 3 4.18x
🐘 Postgres Next.js (Turbopack) 10.800s 11.367s 0.567s 3 4.49x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.567s (-12.0% 🟢) 3.862s (-3.6%) 1.295s 8 1.00x
▲ Vercel Next.js (Turbopack) 2.701s (-21.9% 🟢) 4.004s (-14.7% 🟢) 1.304s 8 1.05x
▲ Vercel Express 3.794s (+21.5% 🔺) 5.064s (+25.7% 🔺) 1.271s 6 1.48x

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

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 3.929s 4.135s 0.206s 8 1.00x
💻 Local Nitro 7.258s (-3.1%) 8.019s (~) 0.762s 4 1.85x
💻 Local Express 7.423s (-1.3%) 8.016s (~) 0.593s 4 1.89x
💻 Local Next.js (Turbopack) 7.486s 7.769s 0.282s 4 1.91x
🌐 MongoDB Next.js (Turbopack) 9.727s 10.352s 0.625s 3 2.48x
🐘 Postgres Express 47.361s (-2.2%) 48.107s (-2.1%) 0.746s 1 12.05x
🐘 Postgres Nitro 48.096s (-5.7% 🟢) 48.117s (-5.9% 🟢) 0.021s 1 12.24x
🐘 Postgres Next.js (Turbopack) 49.877s 50.116s 0.239s 1 12.70x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 3.192s (~) 4.148s (-10.5% 🟢) 0.955s 8 1.00x
▲ Vercel Express 3.249s (-26.1% 🟢) 4.185s (-32.5% 🟢) 0.935s 8 1.02x
▲ Vercel Next.js (Turbopack) 3.799s (-58.3% 🟢) 5.156s (-48.1% 🟢) 1.357s 6 1.19x

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

Promise.race with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 1.210s 2.006s 0.796s 15 1.00x
💻 Local Express 1.417s (-1.1%) 2.006s (~) 0.588s 15 1.17x
💻 Local Next.js (Turbopack) 1.427s 2.005s 0.578s 15 1.18x
💻 Local Nitro 1.461s (+2.2%) 2.006s (~) 0.545s 15 1.21x
🐘 Postgres Nitro 1.920s (-15.4% 🟢) 2.078s (-20.0% 🟢) 0.158s 15 1.59x
🐘 Postgres Next.js (Turbopack) 2.071s 2.596s 0.525s 12 1.71x
🐘 Postgres Express 2.108s (-0.9%) 2.475s (-15.3% 🟢) 0.367s 13 1.74x
🌐 MongoDB Next.js (Turbopack) 2.156s 3.008s 0.853s 10 1.78x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.127s (-74.5% 🟢) 3.048s (-68.8% 🟢) 0.920s 10 1.00x
▲ Vercel Nitro 2.218s (-69.7% 🟢) 3.447s (-59.4% 🟢) 1.229s 9 1.04x
▲ Vercel Next.js (Turbopack) 2.425s (-8.7% 🟢) 3.632s (-4.4%) 1.207s 9 1.14x

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

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 2.360s 3.008s 0.648s 10 1.00x
💻 Local Next.js (Turbopack) 2.599s 3.008s 0.409s 10 1.10x
💻 Local Nitro 2.670s (-1.1%) 3.008s (~) 0.338s 10 1.13x
💻 Local Express 2.689s (~) 3.008s (~) 0.319s 10 1.14x
🌐 MongoDB Next.js (Turbopack) 4.703s 5.177s 0.474s 6 1.99x
🐘 Postgres Nitro 11.509s (+6.1% 🔺) 12.370s (+5.7% 🔺) 0.861s 3 4.88x
🐘 Postgres Next.js (Turbopack) 11.704s 12.364s 0.660s 3 4.96x
🐘 Postgres Express 12.371s (+5.2% 🔺) 12.702s (+2.7%) 0.331s 3 5.24x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.341s (-13.1% 🟢) 3.165s (-22.6% 🟢) 0.823s 10 1.00x
▲ Vercel Nitro 2.689s (~) 4.346s (+19.2% 🔺) 1.657s 7 1.15x
▲ Vercel Next.js (Turbopack) 2.839s (-0.9%) 3.983s (+4.1%) 1.144s 9 1.21x

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

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 3.889s 4.260s 0.371s 8 1.00x
💻 Local Nitro 7.545s (-6.3% 🟢) 8.020s (-5.9% 🟢) 0.476s 4 1.94x
💻 Local Next.js (Turbopack) 7.895s 8.267s 0.372s 4 2.03x
💻 Local Express 8.148s (+3.1%) 9.024s (+2.9%) 0.876s 4 2.10x
🌐 MongoDB Next.js (Turbopack) 9.732s 10.351s 0.619s 3 2.50x
🐘 Postgres Express 49.140s (-3.9%) 50.108s (-3.9%) 0.968s 1 12.64x
🐘 Postgres Nitro 53.097s (+1.9%) 53.121s (~) 0.024s 1 13.65x
🐘 Postgres Next.js (Turbopack) 56.257s 57.116s 0.859s 1 14.47x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.627s (-24.6% 🟢) 3.580s (-19.0% 🟢) 0.953s 9 1.00x
▲ Vercel Next.js (Turbopack) 3.118s (-31.2% 🟢) 4.557s (-17.8% 🟢) 1.439s 7 1.19x
▲ Vercel Nitro 4.048s (+34.3% 🔺) 5.250s (+32.1% 🔺) 1.202s 6 1.54x

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

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 0.110s 1.000s 0.001s 1.007s 0.896s 10 1.00x
💻 Local Next.js (Turbopack) 0.140s 1.001s 0.011s 1.016s 0.876s 10 1.27x
💻 Local Express 0.173s (~) 1.002s (~) 0.011s (+7.5% 🔺) 1.017s (~) 0.844s 10 1.57x
💻 Local Nitro 0.188s (+0.6%) 1.002s (~) 0.010s (-15.8% 🟢) 1.016s (~) 0.828s 10 1.71x
🌐 MongoDB Next.js (Turbopack) 0.500s 0.949s 0.001s 1.009s 0.509s 10 4.53x
🐘 Postgres Express 1.291s (-44.9% 🟢) 1.831s (-32.2% 🟢) 0.002s (+25.0% 🔺) 2.013s (-33.2% 🟢) 0.722s 10 11.70x
🐘 Postgres Next.js (Turbopack) 1.391s 1.655s 0.001s 2.013s 0.622s 10 12.61x
🐘 Postgres Nitro 1.413s (+16.4% 🔺) 1.694s (-7.1% 🟢) 0.002s (+7.1% 🔺) 2.012s (~) 0.600s 10 12.81x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 2.016s (+3.0%) 2.886s (+3.6%) 0.164s (-66.7% 🟢) 3.607s (-5.7% 🟢) 1.591s 10 1.00x
▲ Vercel Nitro 2.051s (+7.7% 🔺) 2.772s (-19.8% 🟢) 0.545s (+310.7% 🔺) 3.939s (-4.5%) 1.888s 10 1.02x
▲ Vercel Express 2.080s (+5.0% 🔺) 2.771s (~) 0.660s (+212.5% 🔺) 3.916s (+10.5% 🔺) 1.836s 10 1.03x

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

Summary

Fastest Framework by World

Winner determined by most benchmark wins

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

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 💻 Local 9/12
Next.js (Turbopack) 🌐 Redis 10/12
Nitro 💻 Local 10/12
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

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