esbuild: Could not resolve import
Fix esbuild "Could not resolve" errors by correcting paths, adding extensions, and configuring aliases, externals, and loader settings.
Symptoms
- Build failed with: Could not resolve "react"
- The import works with a bundler but fails with esbuild
- Errors mention missing extensions or external packages
Possible causes
- The package is not installed or is marked external
- The import path omits an extension esbuild does not guess
- An alias is used but not declared in esbuild resolve settings
- A Node built-in is imported for the browser without a polyfill
Diagnosis steps
Read the exact specifier esbuild names
Interpretation
It shows whether the failure is a package, a relative path, or a Node built-in.
Confirm installation and resolution
node -e "console.log(require.resolve('pkg'))"Interpretation
If Node cannot resolve it, esbuild will not either.
Check resolve and external settings
Interpretation
Aliases, extension guessing, and externals are the usual gaps relative to other bundlers.
Root cause
esbuild resolves imports from its own configuration, not from another tool's settings. Without an explicit alias, extension for non-JS imports, or handling for Node built-ins, a specifier that another bundler resolved becomes unresolvable. Marking a package external also makes esbuild leave it untouched, which fails if the runtime cannot provide it.
Fix
Install missing packages, declare aliases in the esbuild resolve options, and add extensions where needed. For Node built-ins targeted at browsers, provide a polyfill or mark them external appropriately. Review the external list so browser bundles do not reference packages only available in Node.
Verify the fix
Rebuild with esbuild; it resolves every import without error and produces the expected bundle, with no "Could not resolve" messages.
Symptoms
esbuild stops with Could not resolve, naming a specifier. It commonly appears when porting a build from another bundler whose configuration esbuild does not read.
Diagnosis
Note the specifier and verify resolvability:
node -e "console.log(require.resolve('react'))"
Check whether the specifier is a package, a relative path, or a Node built-in.
Fix
Install packages and configure resolution:
import { build } from 'esbuild';
await build({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/bundle.js',
alias: { '@': './src' },
external: ['fs', 'path'], // Node built-ins for a server build
});
Verification
Inspect the bundle output; no “Could not resolve” errors. The build succeeds and the resulting bundle loads without missing-import runtime errors.
Resolution Differs from Runtime
A specifier that resolves at build time is not automatically available at run time, and the reverse is also true. Marking a package external tells esbuild to leave the import in the output, which is correct for a library whose consumers will provide it, but wrong for a browser bundle that has no such package. Conversely, bundling a Node built-in into a browser bundle produces code that references unavailable APIs. Decide per target: bundle what the runtime environment lacks, externalise what the host provides, and align the platform setting so esbuild picks the right condition for browser versus node exports.