esbuild - Quick Reference
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: esbuild for comprehensive documentation.
When NOT to Use This Skill
- Complex applications - Use Vite (which uses esbuild internally)
- Need many plugins - Webpack or Rollup have richer ecosystems
- CSS modules, PostCSS - Vite handles these better
- HMR required - Vite provides full HMR experience
When to Use This Skill
- Ultra-fast simple bundling
- TypeScript library builds
- Understanding how Vite works
- Custom build scripts
Setup
npm install -D esbuild
CLI Usage
# Bundle single file
esbuild src/index.ts --bundle --outfile=dist/bundle.js
# Watch mode
esbuild src/index.ts --bundle --outfile=dist/bundle.js --watch
# Minify for production
esbuild src/index.ts --bundle --minify --outfile=dist/bundle.min.js
# Multiple outputs
esbuild src/index.ts --bundle --outdir=dist --format=esm --format=cjs
# Source maps
esbuild src/index.ts --bundle --sourcemap --outfile=dist/bundle.js
API Usage
// build.ts
import * as esbuild from 'esbuild';
// Simple build
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/bundle.js',
});
// Production build
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
minify: true,
sourcemap: true,
target: ['es2020'],
outfile: 'dist/bundle.min.js',
});
Configuration Options
await esbuild.build({
// Entry points
entryPoints: ['src/index.ts', 'src/worker.ts'],
// Or object for custom names
entryPoints: {
main: 'src/index.ts',
worker: 'src/worker.ts',
},
// Output
bundle: true,
outdir: 'dist',
outfile: 'dist/bundle.js', // Single file
outExtension: { '.js': '.mjs' },
// Format
format: 'esm', // 'esm' | 'cjs' | 'iife'
platform: 'node', // 'browser' | 'node' | 'neutral'
target: ['es2020', 'chrome90', 'firefox88'],
// Optimization
minify: true,
minifyWhitespace: true,
minifyIdentifiers: true,
minifySyntax: true,
treeShaking: true,
// Source maps
sourcemap: true, // External .map file
sourcemap: 'inline', // Inline in JS
sourcemap: 'linked', // External with reference
// Splitting (ESM only)
splitting: true,
chunkNames: 'chunks/[name]-[hash]',
// External packages
external: ['react', 'react-dom'],
packages: 'external', // All node_modules external
// Define
define: {
'process.env.NODE_ENV': '"production"',
'__VERSION__': '"1.0.0"',
},
// Loaders
loader: {
'.png': 'file',
'.svg': 'text',
'.json': 'json',
},
// Paths
alias: {
'@': './src',
'@components': './src/components',
},
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
// Banner/Footer
banner: {
js: '/* Bundle generated at ' + new Date().toISOString() + ' */',
},
footer: {
js: '/* End of bundle */',
},
// Legal comments
legalComments: 'none', // 'none' | 'inline' | 'eof' | 'linked' | 'external'
// Metafile for analysis
metafile: true,
});
Watch Mode (API)
// Watch with rebuild
const ctx = await esbuild.context({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/bundle.js',
});
await ctx.watch();
console.log('Watching for changes...');
// Later: stop watching
await ctx.dispose();
Dev Server
const ctx = await esbuild.context({
entryPoints: ['src/index.tsx'],
bundle: true,
outdir: 'dist',
});
// Start dev server
await ctx.serve({
servedir: 'dist',
port: 3000,
});
console.log('Server running on http://localhost:3000');
Plugins
// Custom plugin structure
const myPlugin: esbuild.Plugin = {
name: 'my-plugin',
setup(build) {
// Resolve hook
build.onResolve({ filter: /^env$/ }, (args) => ({
path: args.path,
namespace: 'env-ns',
}));
// Load hook
build.onLoad({ filter: /.*/, namespace: 'env-ns' }, () => ({
contents: JSON.stringify(process.env),
loader: 'json',
}));
// Start/End hooks
build.onStart(() => {
console.log('Build started');
});
build.onEnd((result) => {
console.log(`Build ended with ${result.errors.length} errors`);
});
},
};
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
plugins: [myPlugin],
outfile: 'dist/bundle.js',
});
Common Plugins
// Environment variables plugin
const envPlugin: esbuild.Plugin = {
name: 'env',
setup(build) {
build.onResolve({ filter: /^env$/ }, (args) => ({
path: args.path,
namespace: 'env-ns',
}));
build.onLoad({ filter: /.*/, namespace: 'env-ns' }, () => ({
contents: `export const API_URL = ${JSON.stringify(process.env.API_URL)}`,
loader: 'ts',
}));
},
};
// CSS modules plugin (basic)
const cssModulesPlugin: esbuild.Plugin = {
name: 'css-modules',
setup(build) {
build.onLoad({ filter: /\.module\.css$/ }, async (args) => {
const css = await fs.readFile(args.path, 'utf8');
// Process CSS modules...
return {
contents: `export default ${JSON.stringify(classNames)}`,
loader: 'js',
};
});
},
};
Library Build
// Build library for npm
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
minify: true,
sourcemap: true,
target: ['es2020'],
external: ['react', 'react-dom'], // Peer deps
outdir: 'dist',
format: 'esm',
outExtension: { '.js': '.mjs' },
});
// Also build CJS
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
minify: true,
sourcemap: true,
target: ['es2020'],
external: ['react', 'react-dom'],
outdir: 'dist',
format: 'cjs',
outExtension: { '.js': '.cjs' },
});
// package.json for library
{
"name": "my-lib",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
}
}
Bundle Analysis
const result = await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
metafile: true,
outfile: 'dist/bundle.js',
});
// Write metafile
await fs.writeFile('meta.json', JSON.stringify(result.metafile));
// Analyze
const analysis = await esbuild.analyzeMetafile(result.metafile);
console.log(analysis);
TypeScript Declaration
// esbuild doesn't generate .d.ts - use tsc
import { execSync } from 'child_process';
// Build JS with esbuild
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/index.js',
});
// Generate types with tsc
execSync('tsc --emitDeclarationOnly --declaration --outDir dist');
Comparison with Other Bundlers
| Feature | esbuild | Webpack | Vite | Rollup |
|---|
| Speed | Fastest | Slow | Fast (uses esbuild) | Medium |
| Config | Simple | Complex | Simple | Medium |
| Plugins | Limited | Many | Many | Many |
| HMR | Basic | Full | Full | Plugin |
| Tree-shaking | Yes | Yes | Yes | Best |
| Code-splitting | ESM only | Full | Full | Full |
When to Use esbuild
| Scenario | Recommendation |
|---|
| Simple bundling | esbuild |
| Library build | esbuild + tsc |
| Complex app | Vite (uses esbuild) |
| Legacy support | Webpack |
| Need plugins | Vite or Rollup |
Anti-Patterns to Avoid
- Do not use for complex apps (use Vite)
- Do not expect advanced HMR
- Do not forget tsc for.d.ts
- Do not ignore external for libraries
Anti-Patterns
| Anti-Pattern | Why It's Bad | Correct Approach |
|---|
| Using for complex apps | Missing features | Use Vite for apps, esbuild for libraries |
| Not externalizing dependencies | Large library bundles | Use external: [...] for peer deps |
| No.d.ts generation | Missing TypeScript types | Run tsc --emitDeclarationOnly |
| Expecting advanced HMR | esbuild HMR is basic | Use Vite's dev server for HMR |
| Not specifying target | Wrong output format | Set target: ['es2020'] explicitly |
| Missing bundle analysis | Unknown bundle size | Use metafile and analyzeMetafile |
Quick Troubleshooting
| Issue | Cause | Solution |
|---|
| "Cannot find module" | Missing external | Add to external array |
| No type definitions | esbuild doesn't generate | Use tsc --emitDeclarationOnly |
| Large bundle | Not externalizing deps | Mark peer deps as external |
| Wrong module format | Incorrect format setting | Set format: 'esm' or 'cjs' |
| Slow builds (unexpected) | Not using esbuild efficiently | Check for plugins causing slowdown |
| CSS not bundled | No CSS loader | esbuild bundles CSS by default, check import |
Performance
# Benchmark (10K modules)
# esbuild: ~0.3s
# Rollup: ~10s
# Webpack: ~30s
Checklist
- Target browsers/node configured
- External packages for libraries
- Minify + sourcemap for production
- Metafile for bundle analysis
- tsc to generate.d.ts
Further Reading
For advanced configurations: mcp__documentation__fetch_docs - Technology: esbuild - esbuild Docs