evanw/esbuild · error · Error
The "wasmModule" option only works in the browser
Error message
The "wasmModule" option only works in the browser
What it means
In the node entry, initialize() (lib/npm/node.ts:235) rejects the wasmModule option, throwing because the native node build spawns a real binary executable and has no use for a precompiled WebAssembly.Module. wasmModule is browser-only (used by the esbuild-wasm/browser build to avoid recompiling the wasm each time).
Source
Thrown at lib/npm/node.ts:235
refs: null,
metafile: typeof metafile === 'string' ? metafile : JSON.stringify(metafile),
options,
callback: (err, res) => { if (err) throw err; result = res! },
}))
return result!
}
export const stop = async () => {
if (stopService) await stopService()
if (workerThreadService) workerThreadService.stop()
}
let initializeWasCalled = false
export let initialize: typeof types.initialize = options => {
options = common.validateInitializeOptions(options || {})
if (options.wasmURL) throw new Error(`The "wasmURL" option only works in the browser`)
if (options.wasmModule) throw new Error(`The "wasmModule" option only works in the browser`)
if (options.worker) throw new Error(`The "worker" option only works in the browser`)
if (initializeWasCalled) throw new Error('Cannot call "initialize" more than once')
ensureServiceIsRunning()
initializeWasCalled = true
return Promise.resolve()
}
interface Service {
build: typeof types.build
context: typeof types.context
transform: typeof types.transform
formatMessages: typeof types.formatMessages
analyzeMetafile: typeof types.analyzeMetafile
}
let defaultWD = process.cwd()
let longLivedService: Service | undefined
let stopService: (() => Promise<void>) | undefinedView on GitHub (pinned to f6058f8364)
Solutions
- Drop wasmModule from the options object when calling initialize in node.
- Skip initialize() in node entirely; the native service starts automatically.
- Use the esbuild-wasm package if you specifically need the WebAssembly module path in node.
Example fix
// before
import * as esbuild from 'esbuild' // native node build
await esbuild.initialize({ wasmModule: mod }) // throws
// after
import * as esbuild from 'esbuild'
await esbuild.build({ entryPoints: ['a.ts'] }) // no initialize / wasmModule needed Defensive patterns
Strategy: validation
Validate before calling
// Remove wasmModule (and other browser-only keys) for node initialize.
function nodeInitOptions(opts) {
const { wasmURL: _a, wasmModule: _b, worker: _c, ...rest } = opts || {}
return rest
}
// Typically you simply do not call initialize() under native esbuild. Type guard
// Narrow options to the node-safe subset (no browser-only keys).
function isNodeSafeOptions(o: any): boolean {
return o.wasmURL === undefined && o.wasmModule === undefined && o.worker === undefined
} Prevention
- Pass wasmModule only when using the browser/esbuild-wasm build.
- Keep a separate config builder for node vs browser initialize calls.
- Rely on node's auto-starting service and avoid initialize() entirely when possible.
When it happens
Trigger: Calling esbuild.initialize({ wasmModule: someCompiledModule }) (or a config object that includes wasmModule) while running the native node esbuild package.
Common situations: A shared config helper for both browser and node that always sets wasmModule; migrating browser code to node without trimming browser-only options; using a precompiled module for performance and forgetting node does not support it.
Related errors
- The "wasmURL" option only works in the browser
- Must provide either the "wasmURL" option or the "wasmModule"
- The "buildSync" API only works in node
- The "transformSync" API only works in node
- The "formatMessagesSync" API only works in node
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/eb99fe6f6af00512.
Report an issue: GitHub.