Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
565712c
[nest] Add buildVercelOutput() for VQS consumer discovery
VaguelySerious Mar 20, 2026
05080bb
[nest] Enable Vercel prod e2e tests for NestJS workbench
VaguelySerious Mar 20, 2026
5b2197e
[nest] Add `workflow-nest build` CLI command, remove manual build script
VaguelySerious Mar 20, 2026
662eb7a
[nest] Fix Vercel build: use turbo to build workspace deps first
VaguelySerious Mar 20, 2026
a4bacda
docs
VaguelySerious Mar 20, 2026
ac0fb21
[nest] Fix bin resolution: use pnpm exec for workspace-linked binaries
VaguelySerious Mar 20, 2026
780bc19
Revert "Add support for calling start() inside workflow functions (#1…
VaguelySerious Mar 21, 2026
c10e4db
Revert "Add support for calling start() inside workflow functions (#1…
VaguelySerious Mar 21, 2026
7265dfc
Merge branch 'peter/revert-start' into peter/nest-fix-mar-20
VaguelySerious Mar 21, 2026
d25b72b
[nest] Fix CLI resolution: use node_modules path instead of pnpm exec
VaguelySerious Mar 21, 2026
05d807f
fix project
VaguelySerious Mar 21, 2026
6ea4b93
[nest] Serve manifest.json as static file in Build Output API
VaguelySerious Mar 21, 2026
6602741
[nest] Add filesystem handler before catch-all route
VaguelySerious Mar 21, 2026
2af862c
[nest] Serve manifest as serverless function instead of static file
VaguelySerious Mar 21, 2026
224f6aa
[nest] Fix manifest routing: use explicit rewrite + renamed function
VaguelySerious Mar 21, 2026
f86a1a9
[nest] Always create manifest function in Build Output API
VaguelySerious Mar 21, 2026
95f6d04
[nest] Add fallback manifest handler and diagnostic logging
VaguelySerious Mar 21, 2026
a6b8422
[nest] Fix manifest routing with handle:miss and correct func name
VaguelySerious Mar 21, 2026
0598241
[nest] Rename manifest function to __manifest to avoid dots in func name
VaguelySerious Mar 21, 2026
290b727
[nest] Skip workflow bundle build on Vercel deployment
VaguelySerious Mar 21, 2026
068d05e
[nest] Rename all .func dirs to avoid dots — fix Build Output API rou…
VaguelySerious Mar 21, 2026
90dc8b9
[nest] Move entry point to _vercel/ to prevent Vercel auto-detection
VaguelySerious Mar 21, 2026
cddac99
[nest] Serve manifest via NestJS controller instead of separate function
VaguelySerious Mar 21, 2026
ef377c8
[nest] Fix manifest serving: use bundle dir as workingDir on Vercel
VaguelySerious Mar 21, 2026
52b89f5
[nest] Hardcode WORKFLOW_PUBLIC_MANIFEST=1 in esbuild bundle
VaguelySerious Mar 21, 2026
f7bd634
[nest] Rename .nestjs/workflow to _workflow in function dir
VaguelySerious Mar 21, 2026
132befe
[nest] Add temporary debug endpoint for manifest investigation
VaguelySerious Mar 21, 2026
784e447
[nest] Improve debug endpoint to search for manifest
VaguelySerious Mar 21, 2026
38f9c4c
[nest] Embed manifest in esbuild banner, write to /tmp at runtime
VaguelySerious Mar 21, 2026
79d192c
debug: search /tmp for manifest
VaguelySerious Mar 21, 2026
d0f3503
[nest] Embed manifest via esbuild wrapper, not /tmp or file copy
VaguelySerious Mar 21, 2026
afe0b18
[nest] Check x-matched-path header for manifest URL matching
VaguelySerious Mar 21, 2026
26942b7
[nest] Check both req.url and x-matched-path for manifest matching
VaguelySerious Mar 21, 2026
fed6016
[nest] Route manifest.json explicitly before handle:filesystem
VaguelySerious Mar 21, 2026
3720d78
debug: add __wf_debug endpoint to wrapper
VaguelySerious Mar 21, 2026
b11d3b3
[nest] Switch NestJS function from ESM to CJS format
VaguelySerious Mar 21, 2026
d01bbaa
[nest] Fix wrapper file extension: use .cjs for CJS format
VaguelySerious Mar 21, 2026
b951ea8
trigger deployment
VaguelySerious Mar 21, 2026
cc1ce20
[nest] Write manifest as static file + remove explicit manifest route
VaguelySerious Mar 21, 2026
6654a6d
[nest] Add continue:true manifest route with content-type header
VaguelySerious Mar 21, 2026
926317e
[nest] Serve manifest via entry point readFileSync + NFT-traced file
VaguelySerious Mar 21, 2026
f28f43a
[nest] Use new URL() pattern for manifest readFileSync (NFT-friendly)
VaguelySerious Mar 21, 2026
2d16f7f
[nest] Inline manifest JSON directly into entry point source
VaguelySerious Mar 21, 2026
03ec698
debug: log req.url in entry point
VaguelySerious Mar 21, 2026
3370227
[nest] Write injected entry to BOTH func dir and source location
VaguelySerious Mar 21, 2026
e14509d
[nest] Use generated __manifest.js module for manifest serving
VaguelySerious Mar 21, 2026
18883d0
[nest] Copy __manifest.js into .func/ dir alongside entry point
VaguelySerious Mar 21, 2026
7ddccb3
debug: add __wf_test diagnostic in entry point
VaguelySerious Mar 21, 2026
3572298
bust turbo cache
VaguelySerious Mar 21, 2026
dbc3d19
trigger rebuild with framework=null
VaguelySerious Mar 21, 2026
7db0d8d
[nest] Add check:true to catch-all route (required after handle:miss)
VaguelySerious Mar 21, 2026
96885ec
[nest] Restore esbuild bundling — required with framework=null
VaguelySerious Mar 21, 2026
f321351
[nest] Use framework=nestjs + __manifest.js import approach
VaguelySerious Mar 21, 2026
5801e8b
[nest] Read manifest from .nestjs/workflow/ via static readFileSync
VaguelySerious Mar 21, 2026
f3d2812
[nest] Add static NFT hint in app.module.ts for manifest inclusion
VaguelySerious Mar 21, 2026
850a594
[nest] Eagerly load manifest at module init + globalThis fallback
VaguelySerious Mar 21, 2026
25068c9
[nest] Fix NFT path: use ../ to resolve from dist/ to project root
VaguelySerious Mar 21, 2026
65e5455
[nest] Use non-dotted workflow-out dir for manifest — NFT may skip do…
VaguelySerious Mar 21, 2026
8509fad
[nest] Fix outDir path: prefix with ./ for enhanced-resolve compat
VaguelySerious Mar 21, 2026
7305ec8
[nest] Copy manifest to dist/ for NFT inclusion
VaguelySerious Mar 21, 2026
c229334
[nest] Use import.meta.url for manifest path resolution
VaguelySerious Mar 21, 2026
feba7cb
[nest] Use new URL() + import.meta.url for NFT-traceable manifest read
VaguelySerious Mar 21, 2026
57538ba
[nest] Use createRequire for manifest — NFT traces require() calls
VaguelySerious Mar 21, 2026
7f211c9
[nest] Run workflow-nest build BEFORE nest build + copy manifest to d…
VaguelySerious Mar 21, 2026
efba6c2
[nest] Add includeFiles for manifest in vercel.json
VaguelySerious Mar 21, 2026
79f62ea
[nest] Fix functions pattern to match _vercel/ directory
VaguelySerious Mar 21, 2026
272fe5b
[nest] Move entry back to api/ for includeFiles support
VaguelySerious Mar 21, 2026
c6f05db
[nest] Read manifest from dist/ via process.cwd() + join
VaguelySerious Mar 21, 2026
fd97fca
[nest] Use dynamic import() for manifest — NFT traces import() calls
VaguelySerious Mar 21, 2026
55dcaf9
[nest] Add @ts-ignore for generated workflow-manifest.js import
VaguelySerious Mar 21, 2026
c0cdd31
[nest] Force-set WORKFLOW_PUBLIC_MANIFEST=1 on Vercel
VaguelySerious Mar 21, 2026
7f6e39f
[nest] Use synchronous createRequire for manifest loading
VaguelySerious Mar 21, 2026
fdf7b6b
[nest] Fix manifest module format: use CJS (module.exports) not ESM
VaguelySerious Mar 21, 2026
cbff199
[nest] Use .cjs extension for manifest module
VaguelySerious Mar 21, 2026
b89e156
[nest] Use .json extension for manifest — require() handles .json nat…
VaguelySerious Mar 21, 2026
2e2f384
[nest] Use createRequire + .json for manifest — works in ESM + Vercel
VaguelySerious Mar 21, 2026
d955038
[nest] Generate manifest in prebuild + NestJS assets copy to dist/
VaguelySerious Mar 21, 2026
a12f10f
[nest] Add configureManifest() API — bypasses readFileSync on Vercel
VaguelySerious Mar 21, 2026
1f84256
[nest] Generate _manifest-data.ts source file for NFT-friendly manifest
VaguelySerious Mar 21, 2026
bf49620
trigger CI
VaguelySerious Mar 21, 2026
c59a5a6
[nest] Include workflow bundles in dist/ via NestJS assets + set outDir
VaguelySerious Mar 22, 2026
a77cf2a
[nest] Try framework=null + @vercel/node for NestJS + Build Output AP…
VaguelySerious Mar 22, 2026
86621a6
[nest] Restore framework=nestjs, remove api/ function and vercel.json…
VaguelySerious Mar 22, 2026
97be350
[nest] Embed workflow bundles as base64 for Vercel Lambda fallback
VaguelySerious Mar 22, 2026
881ade3
update lockfile
VaguelySerious Mar 22, 2026
5ed341a
fix lockfile
VaguelySerious Mar 22, 2026
04953fd
[nest] Use static imports for bundle data — NFT traces static imports
VaguelySerious Mar 22, 2026
5c8ee63
[nest] Write bundles to CWD/.wf_bundles instead of /tmp
VaguelySerious Mar 22, 2026
ac5cfbb
[nest] Symlink node_modules in /tmp for bundle package resolution
VaguelySerious Mar 22, 2026
87a0bd1
[nest] Use self-contained BOA bundles + correct generation order
VaguelySerious Mar 22, 2026
d67d9b9
[nest] Check in placeholder bundle/manifest TS files
VaguelySerious Mar 22, 2026
14edbad
[nest] Use framework=null + esbuild NestJS handler for separate lambd…
VaguelySerious Mar 22, 2026
7d2891e
WIP
VaguelySerious Mar 22, 2026
d1aa9b7
Merge branch 'main' into peter/nest-fix-mar-20
VaguelySerious Mar 23, 2026
5d7ef34
remove nest e2e
VaguelySerious Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nest-vercel-build-output.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@workflow/nest': patch
---

Add `buildVercelOutput()` to `NestLocalBuilder` for generating Vercel Build Output API functions with `experimentalTriggers`, enabling VQS consumer discovery for NestJS deployments
62 changes: 59 additions & 3 deletions docs/content/docs/getting-started/nestjs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,68 @@ WorkflowModule.forRoot({
});
```

## Deploying to production

Workflow DevKit apps currently work best when deployed to [Vercel](https://vercel.com/home) and needs no special configuration.
## Deploying to Vercel

<FluidComputeCallout />

### 1. Create the Vercel entry point

Create a `_vercel/entry.js` file that exports your NestJS app as a serverless function handler. Use `_vercel/` instead of `api/` to avoid triggering Vercel's automatic serverless function detection which conflicts with the Build Output API:

{/*@skip-typecheck - Shows Vercel entry point*/}

```javascript title="_vercel/entry.js" lineNumbers
import { createApp } from '../dist/app.js';

let ready;
async function createHandler() {
const { app } = await createApp();
return app.getHttpAdapter().getInstance();
}

export default async (req, res) => {
ready ??= createHandler();
return (await ready)(req, res);
};
```

<Callout>
Your main app module should export a `createApp()` function that creates and initializes the NestJS application, returning both the app instance and the underlying HTTP adapter.
</Callout>

### 2. Add the build step

Add `workflow-nest build` as a postbuild script. This builds workflow bundles locally, and on Vercel it additionally generates the [Build Output API](https://vercel.com/docs/build-output-api/v3) with the queue triggers that VQS needs to call back your workflow functions:

```json title="package.json" lineNumbers
{
"scripts": {
"prebuild": "npx @workflow/nest init --force",
"build": "nest build",
"postbuild": "workflow-nest build",
"start:dev": "npx @workflow/nest init --force && nest start --watch"
}
}
```

The `workflow-nest build` command auto-detects the `api/index.js` entry point. To specify a different path, use `workflow-nest build --entry path/to/entry.js`.

### 3. Configure Vercel project

Set your Vercel project's **Framework Preset** to **Other** (not "NestJS"). The NestJS preset uses `@vercel/node` which conflicts with the Build Output API that `workflow-nest build` generates.

Your `vercel.json` only needs the build command:

```json title="vercel.json" lineNumbers
{
"buildCommand": "pnpm build"
}
```

<Callout type="warning">
Do **not** set the framework preset to "NestJS" and do not add `functions`, `outputDirectory`, or `rewrites` to `vercel.json` — routing is handled by the generated Build Output API.
</Callout>

Check the [Deploying](/docs/deploying) section to learn how your workflows can be deployed elsewhere.

## Next Steps
Expand Down
85 changes: 79 additions & 6 deletions packages/nest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,61 @@ WorkflowModule.forRoot({
});
```

## Deploying to Vercel

### 1. Create an entry point

Create `_vercel/entry.js` exporting your NestJS app as a handler (use `_vercel/` not `api/` to avoid triggering Vercel's automatic function detection):

```javascript
// _vercel/entry.js
import { createApp } from '../dist/app.js';

let ready;
async function createHandler() {
const { app } = await createApp();
return app.getHttpAdapter().getInstance();
}

export default async (req, res) => {
ready ??= createHandler();
return (await ready)(req, res);
};
```

### 2. Add postbuild script

```json
{
"scripts": {
"prebuild": "npx @workflow/nest init --force",
"build": "nest build",
"postbuild": "workflow-nest build"
}
}
```

`workflow-nest build` builds workflow bundles and, when running on Vercel, generates the [Build Output API](https://vercel.com/docs/build-output-api/v3) with queue triggers so VQS can discover your workflow consumers. The `api/index.js` entry point is auto-detected.

### 3. Configure Vercel project

Set the Framework Preset to **Other** (not "NestJS") — the NestJS preset conflicts with the Build Output API.

```json
{ "buildCommand": "pnpm build" }
```

Do **not** add `functions`, `outputDirectory`, or `rewrites` — the Build Output API handles routing.

## How It Works

The `@workflow/nest` package provides:

1. **WorkflowModule** - A NestJS module that handles workflow bundle building and HTTP routing
2. **WorkflowController** - Handles workflow and step execution requests at `.well-known/workflow/v1/`
3. **NestLocalBuilder** - Builds workflow bundles (steps.mjs, workflows.mjs) from your source files
4. **CLI** - Generates `.swcrc` configuration with the SWC plugin properly resolved
4. **NestLocalBuilder.buildVercelOutput()** - Generates Vercel Build Output API
5. **CLI** - Generates `.swcrc` configuration with the SWC plugin properly resolved

## Why the CLI?

Expand Down Expand Up @@ -178,17 +225,43 @@ WorkflowModule.forRoot({
})
```

### NestLocalBuilder.buildVercelOutput(options)

Generates the Vercel Build Output API.

{/*@skip-typecheck: Shows buildVercelOutput options*/}

```typescript
await builder.buildVercelOutput({
// Path to your Vercel serverless function entry point (required)
entryPoint: 'api/index.js',

// Max duration in seconds for the NestJS function (default: 300)
maxDuration: 300,

// Additional routes for the Build Output API config.json
additionalRoutes: [],
});
```

This generates:

- `.vercel/output/functions/.well-known/workflow/v1/step.func/` with `experimentalTriggers`
- `.vercel/output/functions/.well-known/workflow/v1/flow.func/` with `experimentalTriggers`
- `.vercel/output/functions/.well-known/workflow/v1/webhook/[token].func/`
- `.vercel/output/functions/api/index.js.func/` (bundled NestJS app)
- `.vercel/output/config.json` with routing rules

### CLI Commands

```bash
# Generate .swcrc configuration
npx @workflow/nest init
npx @workflow/nest init --force # overwrite existing

# Force regenerate (overwrites existing)
npx @workflow/nest init --force

# Show help
npx @workflow/nest --help
# Build workflow bundles (+ Vercel Build Output API when VERCEL is set)
npx @workflow/nest build
npx @workflow/nest build --entry api/handler.js # custom entry point
```

## License
Expand Down
Loading
Loading