evanw/esbuild · error · Error
The "wasmURL" option only works in the browser
Error message
The "wasmURL" option only works in the browser
What it means
The Node entry's `initialize` (`node.ts:235`) explicitly rejects the `wasmURL` option because Node uses the native binary and has no need to fetch wasm. The option is browser-only. Passing it means the code was written for the browser API but is running under the Node entry.
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 = () => {
if (stopService) stopService()
if (workerThreadService) workerThreadService.stop()
return Promise.resolve()
}
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 | undefinedView on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Drop the `wasmURL` option when using the `esbuild` package in Node — Node finds the native binary automatically.
- If you genuinely need wasm in Node, use the `esbuild-wasm` package instead.
- Gate initialize options on environment: build the options object conditionally based on `typeof window`.
Example fix
// before (Node script)
import * as esbuild from 'esbuild'
await esbuild.initialize({ wasmURL: '/esbuild.wasm' }) // throws
// after
import * as esbuild from 'esbuild'
// no initialize needed; or:
await esbuild.initialize({}) Defensive patterns
Strategy: validation
Validate before calling
function sanitizeNodeInitOpts(opts: Record<string, unknown>) {
delete opts.wasmURL
delete opts.wasmModule
return opts
} Type guard
function isBrowserInitOpts(o: unknown): boolean {
return !!o && typeof o === 'object' && ('wasmURL' in o || 'wasmModule' in o || 'worker' in o)
} Prevention
- Don't pass browser-only options to the Node esbuild package.
- Build the initialize options object per environment.
- Use esbuild-wasm when you genuinely need wasm in any runtime.
- Document which options are environment-specific in shared code.
When it happens
Trigger: Calling `esbuild.initialize({ wasmURL })` against the Node `esbuild` package (not `esbuild-wasm`). The check fires immediately during option validation.
Common situations: Copy-pasting browser example code into a Node script; sharing initialize code between a browser and Node entry without forking on environment; migrating from esbuild-wasm back to esbuild without removing the option.
Related errors
- The "worker" option only works in the browser
- Must provide either the "wasmURL" option or the "wasmModule"
- The "buildSync" API only works in node
- You need to wait for the promise returned from "initialize"
- The package "${pkg}" could not be found, and is needed by es
AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03).
Data as JSON: /data/errors/f3ff1c4fae1949da.json.
Report an issue: GitHub.