evanw/esbuild · error · Error

The "transformSync" API only works in node

Error message

The "transformSync" API only works in node

What it means

The browser entry of esbuild (lib/npm/browser.ts) defines transformSync as a stub that always throws. The WebAssembly-backed browser build cannot run synchronously, so esbuild blocks the call rather than pretending to work.

Solutions

  1. Use esbuild.transform(...) and await the returned promise.
  2. Switch to the native esbuild package running under node if synchronous execution is required.
  3. Make the calling code async-compatible.

Example fix

// before
const out = esbuild.transformSync(code, { loader: 'ts' })

// after
const out = await esbuild.transform(code, { loader: 'ts' })
Defensive patterns

Strategy: validation

Validate before calling

// Guard against the browser sync stub by using the async transform.
const isBrowserBuild =
  typeof window !== 'undefined' && typeof window.document !== 'undefined'

const out = isBrowserBuild
  ? await esbuild.transform(code, { loader: 'ts' })
  : esbuild.transformSync(code, { loader: 'ts' })

Prevention

When it happens

Trigger: Application code calls esbuild.transformSync(input, options) while the resolved module is the browser build (esbuild-wasm or the package 'browser' field).

Common situations: Copy-pasting node-oriented esbuild usage into a browser bundle; sharing a transform helper module across node and browser targets.

Related errors


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

Appendix: source

Thrown at lib/npm/browser.ts:37

export let context: typeof types.context = (options: types.BuildOptions) =>
  ensureServiceIsRunning().context(options)

export const transform: typeof types.transform = (input: string | Uint8Array, options?: types.TransformOptions) =>
  ensureServiceIsRunning().transform(input, options)

export const formatMessages: typeof types.formatMessages = (messages, options) =>
  ensureServiceIsRunning().formatMessages(messages, options)

export const analyzeMetafile: typeof types.analyzeMetafile = (metafile, options) =>
  ensureServiceIsRunning().analyzeMetafile(metafile, options)

export const buildSync: typeof types.buildSync = () => {
  throw new Error(`The "buildSync" API only works in node`)
}

export const transformSync: typeof types.transformSync = () => {
  throw new Error(`The "transformSync" API only works in node`)
}

export const formatMessagesSync: typeof types.formatMessagesSync = () => {
  throw new Error(`The "formatMessagesSync" API only works in node`)
}

export const analyzeMetafileSync: typeof types.analyzeMetafileSync = () => {
  throw new Error(`The "analyzeMetafileSync" API only works in node`)
}

export const stop = () => {
  if (stopService) stopService()
  return Promise.resolve()
}

interface Service {
  build: typeof types.build
  context: typeof types.context

View on GitHub (pinned to f6058f8364)