Skip to content

Make start() types unknown when deploymentId is provided#1367

Open
pranaygp wants to merge 1 commit intomainfrom
v0/pranaygp-6fadd605
Open

Make start() types unknown when deploymentId is provided#1367
pranaygp wants to merge 1 commit intomainfrom
v0/pranaygp-6fadd605

Conversation

@pranaygp
Copy link
Collaborator

When deploymentId is explicitly provided to start(), the workflow function at that deployment may have different argument and return types than the current codebase. This change splits StartOptions into separate types and adds function overloads so that:

  • Without deploymentId: Full type inference is preserved (TArgs and TResult)
  • With deploymentId: Args become unknown[] and return becomes Run<unknown> to avoid false type expectations

What changed

  • Split StartOptions into StartOptionsBase, StartOptionsWithDeploymentId, and StartOptionsWithoutDeploymentId
  • Added overloads for start() that return Run<unknown> when deploymentId is provided
  • Exported the new option types from runtime.ts
  • Updated docs to explain the type behavior with deploymentId

Slack Thread

Ensure types are 'unknown[]' and 'unknown' for 'deploymentId' and update exports and documentation.

Slack-Thread: https://vercel.slack.com/archives/C09G3EQAL84/p1773368990070059?thread_ts=1773368990.070059&cid=C09G3EQAL84
Co-authored-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com>
@pranaygp pranaygp requested a review from a team as a code owner March 13, 2026 02:34
Copilot AI review requested due to automatic review settings March 13, 2026 02:34
@changeset-bot
Copy link

changeset-bot bot commented Mar 13, 2026

⚠️ No Changeset found

Latest commit: fc5b909

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

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

Click here to learn what changesets are, and how to add one.

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

@vercel
Copy link
Contributor

vercel bot commented Mar 13, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Mar 13, 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.005s (~) 0.973s 10 1.00x
💻 Local Nitro 0.034s (+3.3%) 1.006s (~) 0.972s 10 1.05x
💻 Local Next.js (Turbopack) 0.042s 1.005s 0.963s 10 1.29x
🌐 Redis Next.js (Turbopack) 0.046s 1.005s 0.960s 10 1.41x
🐘 Postgres Next.js (Turbopack) 0.048s 1.011s 0.962s 10 1.49x
🐘 Postgres Express 0.050s (-11.0% 🟢) 1.011s (~) 0.962s 10 1.54x
🐘 Postgres Nitro 0.055s (+3.2%) 1.011s (~) 0.956s 10 1.70x
🌐 MongoDB Next.js (Turbopack) 0.111s 1.007s 0.896s 10 3.44x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 0.423s (-1.5%) 2.589s (+8.0% 🔺) 2.166s 10 1.00x
▲ Vercel Nitro 0.428s (-6.9% 🟢) 2.158s (-10.0% 🟢) 1.730s 10 1.01x
▲ Vercel Next.js (Turbopack) 0.430s (-13.4% 🟢) 1.885s (-8.1% 🟢) 1.455s 10 1.02x

🔍 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.100s 2.006s 0.906s 10 1.00x
💻 Local Express 1.103s (~) 2.006s (~) 0.902s 10 1.00x
💻 Local Next.js (Turbopack) 1.104s 2.005s 0.902s 10 1.00x
💻 Local Nitro 1.110s (+0.6%) 2.006s (~) 0.895s 10 1.01x
🐘 Postgres Next.js (Turbopack) 1.127s 2.012s 0.885s 10 1.02x
🐘 Postgres Express 1.127s (~) 2.011s (~) 0.884s 10 1.02x
🐘 Postgres Nitro 1.130s (+1.3%) 2.013s (~) 0.884s 10 1.03x
🌐 MongoDB Next.js (Turbopack) 1.291s 2.008s 0.717s 10 1.17x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 1.898s (-2.2%) 3.077s (+0.7%) 1.179s 10 1.00x
▲ Vercel Express 1.995s (-6.9% 🟢) 3.605s (-1.6%) 1.610s 10 1.05x
▲ Vercel Nitro 2.061s (-5.1% 🟢) 3.759s (+1.5%) 1.698s 10 1.09x

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

workflow with 10 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 10.643s 11.023s 0.379s 3 1.00x
💻 Local Next.js (Turbopack) 10.686s 11.023s 0.338s 3 1.00x
🐘 Postgres Express 10.774s (~) 11.036s (~) 0.263s 3 1.01x
💻 Local Express 10.788s (~) 11.023s (~) 0.235s 3 1.01x
🐘 Postgres Next.js (Turbopack) 10.819s 11.045s 0.226s 3 1.02x
💻 Local Nitro 10.832s (~) 11.025s (~) 0.193s 3 1.02x
🐘 Postgres Nitro 10.864s (+0.7%) 11.048s (~) 0.184s 3 1.02x
🌐 MongoDB Next.js (Turbopack) 12.207s 13.017s 0.810s 3 1.15x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 16.476s (-1.1%) 18.140s (~) 1.664s 2 1.00x
▲ Vercel Next.js (Turbopack) 16.733s (+1.1%) 17.692s (-1.8%) 0.958s 2 1.02x
▲ Vercel Nitro 18.079s (+7.5% 🔺) 19.824s (+7.7% 🔺) 1.745s 2 1.10x

🔍 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.579s 27.050s 0.472s 3 1.00x
🐘 Postgres Next.js (Turbopack) 26.857s 27.063s 0.206s 3 1.01x
🐘 Postgres Express 26.890s (~) 27.055s (~) 0.164s 3 1.01x
🐘 Postgres Nitro 26.951s (~) 27.058s (~) 0.107s 3 1.01x
💻 Local Next.js (Turbopack) 26.964s 27.052s 0.089s 3 1.01x
💻 Local Express 27.248s (~) 28.054s (~) 0.806s 3 1.03x
💻 Local Nitro 27.316s (~) 28.055s (~) 0.739s 3 1.03x
🌐 MongoDB Next.js (Turbopack) 30.482s 31.040s 0.559s 2 1.15x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 42.115s (-2.4%) 43.192s (-3.1%) 1.076s 2 1.00x
▲ Vercel Express 42.449s (-1.1%) 43.855s (-0.8%) 1.406s 2 1.01x
▲ Vercel Nitro 43.402s (~) 45.006s (+0.7%) 1.604s 2 1.03x

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

workflow with 50 sequential steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 53.115s 53.594s 0.479s 2 1.00x
🐘 Postgres Next.js (Turbopack) 53.620s 54.092s 0.472s 2 1.01x
🐘 Postgres Express 53.721s (~) 54.087s (~) 0.366s 2 1.01x
🐘 Postgres Nitro 53.748s (~) 54.094s (~) 0.347s 2 1.01x
💻 Local Next.js (Turbopack) 55.642s 56.105s 0.463s 2 1.05x
💻 Local Nitro 56.227s (~) 57.107s (+0.9%) 0.880s 2 1.06x
💻 Local Express 56.233s (~) 57.100s (+0.9%) 0.867s 2 1.06x
🌐 MongoDB Next.js (Turbopack) 60.919s 61.082s 0.164s 2 1.15x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Next.js (Turbopack) 91.553s (+0.8%) 93.035s (+1.6%) 1.482s 1 1.00x
▲ Vercel Nitro 93.201s (+2.2%) 94.447s (+1.3%) 1.246s 1 1.02x
▲ Vercel Express 94.153s (+0.5%) 96.181s (+0.8%) 2.028s 1 1.03x

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

Promise.all with 10 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🌐 Redis 🥇 Next.js (Turbopack) 1.238s 2.006s 0.768s 15 1.00x
🐘 Postgres Express 1.312s (-4.4%) 2.010s (~) 0.699s 15 1.06x
🐘 Postgres Nitro 1.352s (+0.8%) 2.010s (~) 0.658s 15 1.09x
🐘 Postgres Next.js (Turbopack) 1.369s 2.010s 0.642s 15 1.11x
💻 Local Nitro 1.396s (-1.5%) 2.005s (~) 0.609s 15 1.13x
💻 Local Express 1.427s (+0.8%) 2.006s (~) 0.579s 15 1.15x
💻 Local Next.js (Turbopack) 1.442s 2.006s 0.564s 15 1.16x
🌐 MongoDB Next.js (Turbopack) 2.136s 3.008s 0.872s 10 1.72x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.358s (+1.9%) 3.912s (+4.2%) 1.554s 8 1.00x
▲ Vercel Next.js (Turbopack) 2.465s (-1.9%) 3.705s (+8.1% 🔺) 1.240s 9 1.05x
▲ Vercel Nitro 2.724s (-3.2%) 4.523s (+3.6%) 1.799s 7 1.16x

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

Promise.all with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 2.437s (-1.6%) 3.011s (~) 0.574s 10 1.00x
🐘 Postgres Nitro 2.466s (-0.8%) 3.013s (~) 0.547s 10 1.01x
🌐 Redis Next.js (Turbopack) 2.510s 3.008s 0.498s 10 1.03x
🐘 Postgres Next.js (Turbopack) 2.565s 3.014s 0.449s 10 1.05x
💻 Local Nitro 2.568s (-4.3%) 3.008s (~) 0.439s 10 1.05x
💻 Local Next.js (Turbopack) 2.682s 3.008s 0.326s 10 1.10x
💻 Local Express 2.733s (+3.9%) 3.008s (~) 0.274s 10 1.12x
🌐 MongoDB Next.js (Turbopack) 4.651s 5.176s 0.525s 6 1.91x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.437s (-11.6% 🟢) 3.856s (-11.2% 🟢) 1.419s 8 1.00x
▲ Vercel Express 2.796s (+12.9% 🔺) 4.260s (+5.6% 🔺) 1.464s 8 1.15x
▲ Vercel Next.js (Turbopack) 2.844s (+5.7% 🔺) 4.001s (+4.0%) 1.157s 8 1.17x

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

Promise.all with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Express 3.867s (-3.8%) 4.300s (-6.2% 🟢) 0.434s 7 1.00x
🌐 Redis Next.js (Turbopack) 4.039s 4.868s 0.829s 7 1.04x
🐘 Postgres Nitro 4.045s (-0.6%) 4.590s (+3.2%) 0.546s 7 1.05x
🐘 Postgres Next.js (Turbopack) 4.141s 5.016s 0.875s 6 1.07x
💻 Local Next.js (Turbopack) 7.047s 7.519s 0.472s 4 1.82x
💻 Local Nitro 7.378s (-5.2% 🟢) 8.019s (~) 0.641s 4 1.91x
💻 Local Express 7.822s (+0.8%) 8.019s (-3.0%) 0.198s 4 2.02x
🌐 MongoDB Next.js (Turbopack) 9.751s 10.348s 0.597s 3 2.52x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.639s (-16.7% 🟢) 3.865s (-9.9% 🟢) 1.226s 8 1.00x
▲ Vercel Express 2.822s (-25.1% 🟢) 4.088s (-20.3% 🟢) 1.266s 8 1.07x
▲ Vercel Next.js (Turbopack) 2.908s (-19.9% 🟢) 4.026s (-20.9% 🟢) 1.117s 8 1.10x

🔍 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.282s 2.006s 0.724s 15 1.00x
🐘 Postgres Express 1.330s (-2.4%) 2.010s (~) 0.680s 15 1.04x
🐘 Postgres Nitro 1.349s (-0.9%) 2.013s (~) 0.664s 15 1.05x
🐘 Postgres Next.js (Turbopack) 1.403s 2.011s 0.608s 15 1.09x
💻 Local Next.js (Turbopack) 1.434s 2.005s 0.571s 15 1.12x
💻 Local Express 1.462s (~) 2.005s (~) 0.544s 15 1.14x
💻 Local Nitro 1.476s (+2.3%) 2.006s (~) 0.530s 15 1.15x
🌐 MongoDB Next.js (Turbopack) 2.144s 3.009s 0.864s 10 1.67x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 2.148s (+4.2%) 3.782s (+5.0% 🔺) 1.635s 8 1.00x
▲ Vercel Express 2.148s (-8.5% 🟢) 3.676s (-3.1%) 1.528s 9 1.00x
▲ Vercel Next.js (Turbopack) 2.225s (+2.0%) 3.410s (+0.6%) 1.185s 9 1.04x

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

Promise.race with 25 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 2.453s (-3.3%) 3.012s (-3.2%) 0.559s 10 1.00x
🐘 Postgres Express 2.467s (~) 3.010s (~) 0.543s 10 1.01x
🌐 Redis Next.js (Turbopack) 2.511s 3.008s 0.497s 10 1.02x
🐘 Postgres Next.js (Turbopack) 2.538s 3.013s 0.474s 10 1.03x
💻 Local Next.js (Turbopack) 2.641s 3.008s 0.367s 10 1.08x
💻 Local Nitro 2.670s (-4.0%) 3.008s (-3.2%) 0.338s 10 1.09x
💻 Local Express 2.831s (-1.4%) 3.009s (-3.2%) 0.179s 10 1.15x
🌐 MongoDB Next.js (Turbopack) 4.756s 5.344s 0.588s 6 1.94x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.488s (-9.8% 🟢) 3.974s (-9.0% 🟢) 1.486s 9 1.00x
▲ Vercel Nitro 2.810s (+14.4% 🔺) 4.139s (+6.9% 🔺) 1.329s 8 1.13x
▲ Vercel Next.js (Turbopack) 3.169s (+15.0% 🔺) 4.492s (+16.0% 🔺) 1.322s 7 1.27x

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

Promise.race with 50 concurrent steps

💻 Local Development

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
🐘 Postgres 🥇 Nitro 3.928s (-2.9%) 4.590s (~) 0.661s 7 1.00x
🐘 Postgres Express 4.015s (+0.8%) 4.587s (+3.2%) 0.572s 7 1.02x
🌐 Redis Next.js (Turbopack) 4.084s 4.725s 0.641s 7 1.04x
🐘 Postgres Next.js (Turbopack) 4.111s 5.015s 0.904s 6 1.05x
💻 Local Next.js (Turbopack) 7.739s 8.267s 0.528s 4 1.97x
💻 Local Nitro 7.764s (-8.5% 🟢) 8.021s (-11.1% 🟢) 0.257s 4 1.98x
💻 Local Express 8.407s (+1.8%) 9.021s (~) 0.614s 4 2.14x
🌐 MongoDB Next.js (Turbopack) 9.908s 10.348s 0.440s 3 2.52x

▲ Production (Vercel)

World Framework Workflow Time Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Express 2.761s (-1.9%) 4.298s (+6.0% 🔺) 1.537s 7 1.00x
▲ Vercel Nitro 2.835s (-8.0% 🟢) 4.537s (+0.6%) 1.701s 7 1.03x
▲ Vercel Next.js (Turbopack) 2.960s (-5.4% 🟢) 4.219s (-2.6%) 1.258s 8 1.07x

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

Stream Benchmarks (includes TTFB metrics)
workflow with stream

💻 Local Development

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
💻 Local 🥇 Next.js (Turbopack) 0.146s 1.002s 0.012s 1.018s 0.872s 10 1.00x
🌐 Redis Next.js (Turbopack) 0.153s 1.000s 0.002s 1.007s 0.855s 10 1.04x
🐘 Postgres Express 0.173s (-8.4% 🟢) 0.994s (~) 0.001s (-6.7% 🟢) 1.012s (~) 0.839s 10 1.18x
🐘 Postgres Next.js (Turbopack) 0.174s 1.001s 0.002s 1.013s 0.839s 10 1.19x
💻 Local Express 0.175s (~) 1.003s (~) 0.012s (+2.6%) 1.018s (~) 0.843s 10 1.20x
💻 Local Nitro 0.179s (+3.7%) 1.003s (~) 0.011s (-8.6% 🟢) 1.017s (~) 0.837s 10 1.23x
🐘 Postgres Nitro 0.199s (+5.5% 🔺) 0.996s (~) 0.001s (-13.3% 🟢) 1.014s (~) 0.815s 10 1.36x
🌐 MongoDB Next.js (Turbopack) 0.501s 0.945s 0.001s 1.009s 0.509s 10 3.42x

▲ Production (Vercel)

World Framework Workflow Time TTFB Slurp Wall Time Overhead Samples vs Fastest
▲ Vercel 🥇 Nitro 1.545s (+2.1%) 2.388s (-3.4%) 0.004s (~) 2.953s (-2.0%) 1.408s 10 1.00x
▲ Vercel Express 1.569s (-1.6%) 2.387s (+4.9%) 0.007s (+53.2% 🔺) 2.891s (+3.2%) 1.322s 10 1.02x
▲ Vercel Next.js (Turbopack) 1.581s (+5.8% 🔺) 2.522s (-2.7%) 0.006s (+26.5% 🔺) 2.935s (-2.8%) 1.354s 10 1.02x

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

Summary

Fastest Framework by World

Winner determined by most benchmark wins

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

Winner determined by most benchmark wins

Framework 🥇 Fastest World Wins
Express 🐘 Postgres 8/12
Next.js (Turbopack) 🌐 Redis 8/12
Nitro 🐘 Postgres 5/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

@github-actions
Copy link
Contributor

github-actions bot commented Mar 13, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 560 0 67 627
✅ 💻 Local Development 600 0 84 684
✅ 📦 Local Production 600 0 84 684
✅ 🐘 Local Postgres 600 0 84 684
✅ 🪟 Windows 54 0 3 57
❌ 🌍 Community Worlds 116 55 15 186
✅ 📋 Other 144 0 27 171
Total 2674 55 364 3093

❌ Failed Tests

🌍 Community Worlds (55 failed)

mongodb (3 failed):

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

redis (2 failed):

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

turso (50 failed):

  • addTenWorkflow
  • addTenWorkflow
  • wellKnownAgentWorkflow (.well-known/agent)
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • importedStepOnlyWorkflow
  • hookWorkflow
  • hookWorkflow is not resumable via public webhook endpoint
  • 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 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
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running
  • 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
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control)

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 50 0 7
✅ example 50 0 7
✅ express 50 0 7
✅ fastify 50 0 7
✅ hono 50 0 7
✅ nextjs-turbopack 55 0 2
✅ nextjs-webpack 55 0 2
✅ nitro 50 0 7
✅ nuxt 50 0 7
✅ sveltekit 50 0 7
✅ vite 50 0 7
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 48 0 9
✅ express-stable 48 0 9
✅ fastify-stable 48 0 9
✅ hono-stable 48 0 9
✅ nextjs-turbopack-canary 54 0 3
✅ nextjs-turbopack-stable 54 0 3
✅ nextjs-webpack-canary 54 0 3
✅ nextjs-webpack-stable 54 0 3
✅ nitro-stable 48 0 9
✅ nuxt-stable 48 0 9
✅ sveltekit-stable 48 0 9
✅ vite-stable 48 0 9
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 48 0 9
✅ express-stable 48 0 9
✅ fastify-stable 48 0 9
✅ hono-stable 48 0 9
✅ nextjs-turbopack-canary 54 0 3
✅ nextjs-turbopack-stable 54 0 3
✅ nextjs-webpack-canary 54 0 3
✅ nextjs-webpack-stable 54 0 3
✅ nitro-stable 48 0 9
✅ nuxt-stable 48 0 9
✅ sveltekit-stable 48 0 9
✅ vite-stable 48 0 9
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 48 0 9
✅ express-stable 48 0 9
✅ fastify-stable 48 0 9
✅ hono-stable 48 0 9
✅ nextjs-turbopack-canary 54 0 3
✅ nextjs-turbopack-stable 54 0 3
✅ nextjs-webpack-canary 54 0 3
✅ nextjs-webpack-stable 54 0 3
✅ nitro-stable 48 0 9
✅ nuxt-stable 48 0 9
✅ sveltekit-stable 48 0 9
✅ vite-stable 48 0 9
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 54 0 3
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 2
❌ mongodb 51 3 3
✅ redis-dev 3 0 2
❌ redis 52 2 3
✅ turso-dev 3 0 2
❌ turso 4 50 3
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 48 0 9
✅ e2e-local-postgres-nest-stable 48 0 9
✅ e2e-local-prod-nest-stable 48 0 9

📋 View full workflow run

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

Adjusts @workflow/core’s start() TypeScript API so that providing an explicit deploymentId no longer implies compile-time argument/return type compatibility with the local workflow code, avoiding misleading type inference when targeting other deployments.

Changes:

  • Split StartOptions into StartOptionsBase, StartOptionsWithDeploymentId, and StartOptionsWithoutDeploymentId.
  • Added start() overloads so deploymentId calls use unknown[] args and return Promise<Run<unknown>>.
  • Exported the new option types from packages/core/src/runtime.ts and documented the unknown typing behavior.

Reviewed changes

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

File Description
packages/core/src/runtime/start.ts Refactors start option types and adds overloads to switch to unknown typing when deploymentId is provided.
packages/core/src/runtime.ts Re-exports the newly split start option types.
docs/content/docs/api-reference/workflow-api/start.mdx Documents that passing deploymentId makes args/return type unknown.

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

You can also share your feedback on Copilot code review. Take the survey.

*/
specVersion?: number;
export interface StartOptionsWithoutDeploymentId extends StartOptionsBase {
deploymentId?: undefined;
Comment on lines +83 to +90
export function start(
workflow: WorkflowFunction<unknown[], unknown> | WorkflowMetadata,
args: unknown[],
options: StartOptionsWithDeploymentId
): Promise<Run<unknown>>;

export function start(
workflow: WorkflowFunction<unknown[], unknown> | WorkflowMetadata,
): Promise<Run<unknown>>;

export function start(
workflow: WorkflowFunction<unknown[], unknown> | WorkflowMetadata,
@karthikscale3
Copy link
Collaborator

Claude flagged a blocker and some more comments:

PR #1367 Review: Make start() types unknown when deploymentId is provided

Intent: When deploymentId is explicitly provided to start(), the workflow at that deployment may have different types than the current codebase, so args/return types should be unknown.

Blocker

Overload with WorkflowFunction<unknown[], unknown> is too restrictive under strictFunctionTypes

The deploymentId overloads use WorkflowFunction<unknown[], unknown> for the workflow parameter:

// (from the PR diff - new overloads)
export function start(
  workflow: WorkflowFunction<unknown[], unknown> | WorkflowMetadata,
  args: unknown[],
  options: StartOptionsWithDeploymentId
): Promise<Run<unknown>>;

export function start(
  workflow: WorkflowFunction<unknown[], unknown> | WorkflowMetadata,
  options: StartOptionsWithDeploymentId
): Promise<Run<unknown>>;

Due to TypeScript's function parameter contravariance under strictFunctionTypes, a typed workflow like WorkflowFunction<[number], string> (i.e., (n: number) => Promise<string>) is not assignable to WorkflowFunction<unknown[], unknown> (i.e., (...args: unknown[]) => Promise<unknown>). This means:

import { myWorkflow } from './workflows/my-workflow'; // WorkflowFunction<[string], number>
start(myWorkflow, ['hello'], { deploymentId: 'dpl_xxx' }); // TYPE ERROR

This defeats the purpose of the PR since the main use case is calling start() with an existing typed workflow but targeting a different deployment. The fix would be to use WorkflowFunction<any[], any> in those overloads, or use a generic that still returns Run<unknown>:

export function start<TArgs extends unknown[], TResult>(
  workflow: WorkflowFunction<TArgs, TResult> | WorkflowMetadata,
  args: unknown[],
  options: StartOptionsWithDeploymentId
): Promise<Run<unknown>>;

(Copilot's review comment #2 flagged the same issue.)

Potential Regressions

  1. Breaking change for string | undefined deploymentId values -- The split into StartOptionsWithDeploymentId (required deploymentId) and StartOptionsWithoutDeploymentId (deploymentId?: undefined) means code like this no longer compiles:

    const maybeDeploymentId: string | undefined = getConfig();
    start(wf, args, { deploymentId: maybeDeploymentId }); // TYPE ERROR

    Since deploymentId is @deprecated and documented as "should not be set in user code", this is likely acceptable, but worth noting.

  2. Sub-types not re-exported from workflow/api -- The new types StartOptionsBase, StartOptionsWithDeploymentId, StartOptionsWithoutDeploymentId are exported from @workflow/core/runtime but the user-facing packages/workflow/src/api.ts only re-exports StartOptions. If users need these types, they'd have to import from @workflow/core directly.

Minor Issues

  1. Changeset message is misleading -- The changeset says "Deprecate deploymentId in StartOptions with warning that it should not be set by users", but the actual change is about making types unknown when deploymentId is provided. The changeset message should match the actual behavior change.

  2. No type-level tests -- There are no expectTypeOf or @ts-expect-error assertions to verify the overload resolution works correctly in both branches (with and without deploymentId). Given the subtlety of the contravariance issue, type-level tests would be valuable to prevent regressions.

Verdict

The contravariance issue with the deploymentId overloads (issue #1) is a blocker -- users with typed workflows won't be able to call start() with deploymentId at all, which is the entire purpose of the PR. The other items are minor but worth addressing.

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