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.

src/app.module.ts
import { Module } from "@nestjs/common";
import { WorkflowModule } from "workflow/nest";

@Module({
  imports: [WorkflowModule.forRoot()],
})
export class AppModule {}

If your NestJS project compiles to CommonJS via SWC, pass moduleType and distDir so the builder can rewrite imports in the generated bundles:

src/app.module.ts
import { Module } from "@nestjs/common";
import { WorkflowModule } from "workflow/nest";

@Module({
  imports: [
    WorkflowModule.forRoot({
      moduleType: "commonjs",
      distDir: "dist",
    }),
  ],
})
export class AppModule {}

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.

src/app.module.ts
WorkflowModule.forRootAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ({
    basePath: config.get("API_PREFIX"),
  }),
});
ParameterTypeDescription
importsunknown[]Optional. Modules whose exported providers the factory injects.
injectunknown[]Optional. Providers passed to useFactory, in order.
useFactory(...args) => WorkflowModuleOptions | Promise<WorkflowModuleOptions>Returns the module options.

Parameters

ParameterTypeDescription
optionsWorkflowModuleOptionsOptional. Configures the workflow build.

WorkflowModuleOptions

Extends NestBuilderOptions: all builder options are accepted, plus skipBuild:

OptionTypeDefaultDescription
skipBuildbooleantrue when VERCEL is set, else falseSkip building workflow bundles on startup. The bundles must already exist; startup fails with an explicit error if they do not.
basePathstringadopted 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.
manageWorldLifecyclebooleanfalseStart 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.
preloadBundlesbooleanfalse when VERCEL is set, else trueLoad the generated bundles during startup instead of on the first request. On Vercel, dedicated functions serve the bundles, so there is nothing to preload.
bypassBodyParserbooleantrueKeep 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.
workingDirstringprocess.cwd()Working directory for the NestJS application.
dirsstring[]['src']Directories to scan for workflow files.
outDirstring'.nestjs/workflow' (relative to workingDir)Output directory for generated workflow bundles.
watchbooleanfalseDeprecated 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.
distDirstring'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.
sourcemapboolean | '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:

src/some.service.ts
import { Inject, Injectable } from "@nestjs/common";
import {
  WORKFLOW_MODULE_OPTIONS,
  type WorkflowModuleOptions,
} from "workflow/nest";

@Injectable()
export class SomeService {
  constructor(
    @Inject(WORKFLOW_MODULE_OPTIONS)
    private readonly options: WorkflowModuleOptions
  ) {}
}

The older WORKFLOW_OPTIONS token resolves to the same value and is kept for compatibility.

Lifecycle

HookBehaviour
onModuleInitTakes 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.
onApplicationShutdownCloses 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.