workflow
Version:
Workflow SDK - Build durable, resilient, and observable workflows
121 lines (85 loc) • 5.18 kB
text/mdx
---
title: node-js-module-in-workflow
description: Move Node.js core module usage to step functions instead of workflows.
type: troubleshooting
summary: Resolve the node-js-module-in-workflow error by moving Node.js modules to step functions.
prerequisites:
- /docs/foundations/workflows-and-steps
related:
- /docs/how-it-works/understanding-directives
---
<CopyPrompt
text="Fix Node.js module usage inside workflow functions. Search workflow files for imports or direct usage of Node-only APIs such as `fs`, `path`, `crypto`, `process`, `http`, or SDK clients. Remove those imports from files/functions that execute under `"use workflow"`. Create helper functions with `"use step"` for filesystem, crypto, environment, network, database, or SDK work, and call those helpers from the workflow. Keep the workflow function limited to deterministic orchestration, serializable values, `sleep`, hooks, and step calls. Verify the workflow starts without node-js-module-in-workflow errors."
/>
This error occurs when you try to import or use Node.js core modules (like `fs`, `http`, `crypto`, `path`, etc.) directly inside a workflow function.
## Error message
```text
Cannot use Node.js module "fs" in workflow functions. Move this module to a step function.
```
## Why this happens
Workflow functions run in a sandboxed environment without full Node.js runtime access. This restriction is important for maintaining **determinism** - the ability to replay workflows exactly and resume from where they left off after suspensions or failures.
Node.js modules have side effects and non-deterministic behavior that could break workflow replay guarantees.
## Transitive dependencies and dynamic `require()`
The same error is reported for a module the workflow bundle could not inline, even when your own code never imports it directly:
```text
Workflow bundle cannot run in the workflow sandbox.
Imports left external (1):
• "node:fs"
imported by node_modules/leaky-pkg/index.js
via app/workflows/order.ts → node_modules/wrapper-pkg/index.js → node_modules/leaky-pkg/index.js
Unresolved require() calls (1):
• dynamic require() in node_modules/lazy-pkg/index.js (bundle 412:31)
```
The workflow sandbox has no `require`, so both would throw `ReferenceError: require is not defined` when the bundle loads. Follow the import chain to the first file you own and move that work into a step function, or replace a dynamic `require()` with a static import so the bundler can inline it.
A `require()` wrapped in `try`/`catch`, or behind a `typeof require` check, is not reported — that is how packages probe for an optional dependency or for a CommonJS environment, and in the sandbox the error is caught or the call never runs:
```js
try {
loadOptional(require("@emotion/is-prop-valid").default);
} catch {
// optional dependency, fall back
}
if (typeof require !== "undefined") {
crypto = require("crypto");
}
```
A `typeof require` check only excuses the branch it skips when `require` is undefined, so `typeof require === "undefined" ? require(x) : y` is still reported. A `try` only counts when it has a `catch`. The checks read the code's structure without running it, so a `catch` that rethrows the error is still treated as a guard, and the bundle fails at runtime if that code is reached.
As a last resort — for example a `require()` that can never run — set `WORKFLOW_ALLOW_UNSAFE_FLOW_BUNDLE=1` to downgrade the build failure to a warning. The bundle still fails at runtime if the code is reached.
## Quick fix
Move any code using Node.js modules to a step function. Step functions have full Node.js runtime access.
For example, when trying to read a file in a workflow function, you should move the code to a step function.
**Before:**
```typescript lineNumbers
import * as fs from "fs";
export async function processFileWorkflow(filePath: string) {
"use workflow";
// This will cause an error - Node.js module in workflow context
const content = fs.readFileSync(filePath, "utf-8"); // [!code highlight]
return content;
}
```
**After:**
```typescript lineNumbers
import * as fs from "fs";
export async function processFileWorkflow(filePath: string) {
"use workflow";
// Call step function that has Node.js access
const content = await read(filePath); // [!code highlight]
return content;
}
async function read(filePath: string) {
"use step";
// Node.js modules are allowed in step functions
return fs.readFileSync(filePath, "utf-8"); // [!code highlight]
}
```
## Common Node.js modules
These common Node.js core modules cannot be used in workflow functions:
- File system: `fs`, `path`
- Network: `http`, `https`, `net`, `dns`
- Process: `child_process`, `cluster`
- Crypto: `crypto` (use Web Crypto API instead)
- Operating system: `os`
- Streams: `stream` (use Web Streams API instead)
<Callout type="info">
You can use Web Platform APIs in workflow functions (like `Headers`, `crypto.randomUUID()`, `Response`, etc.), since these are available in the sandboxed environment. See [Workflow Globals](/docs/api-reference/workflow-globals) for the full list.
</Callout>