WorkflowModule
NestJS module that provides workflow functionality. It builds the workflow bundles on module initialization (onModuleInit) and registers the WorkflowController that serves the workflow runtime routes.
Usage
Add WorkflowModule.forRoot() to the imports array of your root module.
If your NestJS project compiles to CommonJS via SWC, pass moduleType and distDir so the builder can rewrite imports in the generated bundles:
API signature
Static methods
forRoot(options?)
Configures the module and returns a NestJS DynamicModule registered as global. It provides the resolved options under the WORKFLOW_MODULE_OPTIONS token, and (unless skipBuild is set) creates a NestLocalBuilder that builds the workflow bundles when the module initializes.
forRootAsync(options)
Same as forRoot, with the options produced by a factory so they can come from other providers.
| Parameter | Type | Description |
|---|---|---|
imports | unknown[] | Optional. Modules whose exported providers the factory injects. |
inject | unknown[] | Optional. Providers passed to useFactory, in order. |
useFactory | (...args) => WorkflowModuleOptions | Promise<WorkflowModuleOptions> | Returns the module options. |
Parameters
| Parameter | Type | Description |
|---|---|---|
options | WorkflowModuleOptions | Optional. Configures the workflow build. |
WorkflowModuleOptions
Extends NestBuilderOptions: all builder options are accepted, plus skipBuild:
| Option | Type | Default | Description |
|---|---|---|---|
skipBuild | boolean | true when VERCEL is set, else false | Skip building workflow bundles on startup. The bundles must already exist; startup fails with an explicit error if they do not. |
basePath | string | adopted from app.setGlobalPrefix() | Route prefix the workflow endpoints are served under, applied to generated callback and webhook URLs. Set it when a reverse proxy mounts the app on a sub-path NestJS cannot see. |
manageWorldLifecycle | boolean | false | Start the target World's background workers with the app and close them on shutdown. Required for self-hosted Worlds, which otherwise never pick up runs. |
preloadBundles | boolean | false when VERCEL is set, else true | Load the generated bundles during startup instead of on the first request. On Vercel, dedicated functions serve the bundles, so there is nothing to preload. |
bypassBodyParser | boolean | true | Keep the application's body parsers away from .well-known/workflow/v1, so queue deliveries are not rejected by Express's 100 KB limit and signed webhook bodies stay byte-exact. The application's own routes are untouched. On Fastify, where the body limit is enforced per instance rather than per route, nothing is patched and a limit low enough to reject deliveries is reported at startup instead. |
workingDir | string | process.cwd() | Working directory for the NestJS application. |
dirs | string[] | ['src'] | Directories to scan for workflow files. |
outDir | string | '.nestjs/workflow' (relative to workingDir) | Output directory for generated workflow bundles. |
watch | boolean | false | Deprecated and ignored. Watch mode is not implemented for this builder. Use nest start --watch, which re-runs the startup build. |
moduleType | 'es6' | 'commonjs' | 'es6' | SWC module compilation type. Set to 'commonjs' if your NestJS project compiles to CommonJS (CJS) through SWC. |
distDir | string | 'dist' | Directory where NestJS compiles .ts source files to .js (relative to workingDir). Used when moduleType is 'commonjs'. Should match the outDir in your tsconfig.json. |
sourcemap | boolean | 'inline' | 'linked' | 'external' | 'both' | 'inline' (dev) / false (prod) | Controls source maps on generated workflow bundles. Defaults to 'inline' in development and false in production. Can also be set via the WORKFLOW_SOURCEMAP environment variable. |
Returns
forRoot() and forRootAsync() return a DynamicModule to include in the imports array of your root module.
Injecting the resolved options
Both factories export the resolved options under WORKFLOW_MODULE_OPTIONS:
The older WORKFLOW_OPTIONS token resolves to the same value and is kept for compatibility.
Lifecycle
| Hook | Behaviour |
|---|---|
onModuleInit | Takes the application's body parsers off the workflow routes (unless bypassBodyParser is false), reconciles the base path against app.setGlobalPrefix(), builds the bundles (or verifies they exist when skipBuild is set), optionally starts the World, and preloads the bundles. |
onApplicationShutdown | Closes the World when manageWorldLifecycle is set. Call app.enableShutdownHooks() so this runs on a signal. |
WorkflowModule reads NestJS's global prefix and HTTP adapter through the
injector, which only works while a single copy of @nestjs/core is installed.
With two copies the injection tokens differ, prefix handling and the
body-parser bypass both stop working, and a warning is logged at startup.
Workflows and steps run outside the NestJS injector, so providers cannot be injected into "use workflow" or "use step" code. See NestJS dependency injection is not available in workflows and steps.