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>) | undefined

View on GitHub (pinned to f6058f8364)

Solutions

  1. Drop wasmModule from the options object when calling initialize in node.
  2. Skip initialize() in node entirely; the native service starts automatically.
  3. 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

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


AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09). Data as JSON: /api/errors/eb99fe6f6af00512. Report an issue: GitHub.