workflow
Version:
Workflow SDK - Build durable, resilient, and observable workflows
140 lines (105 loc) • 5 kB
text/mdx
---
title: withWorkflow
description: Configure webpack/turbopack to transform workflow directives in Next.js.
type: reference
summary: Wrap your Next.js config with withWorkflow to enable workflow directive transformation.
prerequisites:
- /docs/getting-started/next
---
Configures webpack/turbopack loaders to transform workflow code (`"use step"`/`"use workflow"` directives)
## Usage
To enable `"use step"` and `"use workflow"` directives while developing locally or deploying to production, wrap your `nextConfig` with `withWorkflow`.
```typescript title="next.config.ts" lineNumbers
import { withWorkflow } from "workflow/next"; // [!code highlight]
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
// … rest of your Next.js config
};
// not required but allows configuring workflow options
const workflowConfig = {}
export default withWorkflow(nextConfig, workflowConfig); // [!code highlight]
```
<Callout type="warn">
If a package in `serverExternalPackages` contains workflow code (`"use step"`,
`"use workflow"`, or serialization classes), `withWorkflow()` automatically
removes it from `serverExternalPackages` for the current build and prints a
warning. Workflow still compiles the package so its directives are transformed.
Remove that package from `serverExternalPackages` in your
`next.config` to silence the warning.
</Callout>
### Workflow Discovery in Next.js
`withWorkflow()` discovers workflows by scanning your Next.js entrypoints — App
Router `route`, `page`, and `layout` files (under `app/` or `src/app/`) and any
file under `pages/` or `src/pages/` — for `start()` calls imported from
`workflow/api`. The workflow and step files themselves can live anywhere (for
example `src/workflows/`); they are discovered transitively through imports, as
long as a `start()` call in an entrypoint statically reaches them.
<Callout type="info">
Call `start()` from server-side entrypoints, including Route Handlers and Server
Actions. Don't call workflow functions directly — that bypasses the workflow
runtime.
</Callout>
### Next.js Server Actions and `"use server"`
Don't put a top-level `"use server"` directive in modules imported by workflow
or step functions. Workflow transformation wraps imported modules in synchronous
initializers, and Next.js rejects a `"use server"` directive inside that wrapper
with errors like `Server Actions must be async functions`. Keep `"use server"`
on the files that define your Server Actions, and move shared logic into
separate modules that don't carry the directive.
### Monorepos and Workspace Imports
By default, Next.js detects the correct workspace root automatically. If your Next.js app lives in a subdirectory such as `apps/web` and workspace resolution is not working correctly, you can set `outputFileTracingRoot` as a workaround:
```typescript title="apps/web/next.config.ts" lineNumbers
import { resolve } from "node:path";
import type { NextConfig } from "next";
import { withWorkflow } from "workflow/next";
const nextConfig: NextConfig = {
outputFileTracingRoot: resolve(process.cwd(), "../.."),
};
export default withWorkflow(nextConfig);
```
<Callout type="info">
Use the smallest directory that contains every workspace package imported by your workflows. If your app already lives at the repository root, you do not need to set `outputFileTracingRoot`.
</Callout>
## Options
`withWorkflow` accepts an optional second argument to configure the Next.js integration.
```typescript title="next.config.ts" lineNumbers
import type { NextConfig } from "next";
import { withWorkflow } from "workflow/next";
const nextConfig: NextConfig = {};
export default withWorkflow(nextConfig, {
workflows: {
local: {
port: 4000,
},
},
});
```
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `workflows.local.port` | `number` | — | Overrides the `PORT` environment variable for local development. Has no effect when deployed to Vercel. |
<Callout type="info">
The `workflows.local` options only affect local development. When deployed to Vercel, the runtime ignores `local` settings and uses the Vercel world automatically.
</Callout>
## Exporting a Function
If you are exporting a function in your `next.config` you will need to ensure you call the function returned from `withWorkflow`.
```typescript title="next.config.ts" lineNumbers
import { NextConfig } from "next";
import { withWorkflow } from "workflow/next";
import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin();
export default async function config(
phase: string,
ctx: {
defaultConfig: NextConfig
}
): Promise<NextConfig> {
let nextConfig: NextConfig | typeof config = {};
for (const configModifier of [withNextIntl, withWorkflow]) {
nextConfig = configModifier(nextConfig);
if (typeof nextConfig === "function") {
nextConfig = await nextConfig(phase, ctx);
}
}
return nextConfig;
}
```