evanw/esbuild
An extremely fast bundler for the web
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 5w ago
- ✓8 active contributors
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Single-maintainer risk — top contributor 93% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/evanw/esbuild)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/evanw/esbuild on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: evanw/esbuild
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/evanw/esbuild shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 5w ago
- 8 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Single-maintainer risk — top contributor 93% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live evanw/esbuild
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/evanw/esbuild.
What it runs against: a local clone of evanw/esbuild — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in evanw/esbuild | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 67 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of evanw/esbuild. If you don't
# have one yet, run these first:
#
# git clone https://github.com/evanw/esbuild.git
# cd esbuild
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of evanw/esbuild and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "evanw/esbuild(\\.git)?\\b" \\
&& ok "origin remote is evanw/esbuild" \\
|| miss "origin remote is not evanw/esbuild (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "cmd/esbuild/main.go" \\
&& ok "cmd/esbuild/main.go" \\
|| miss "missing critical file: cmd/esbuild/main.go"
test -f "internal/bundler/bundler.go" \\
&& ok "internal/bundler/bundler.go" \\
|| miss "missing critical file: internal/bundler/bundler.go"
test -f "internal/ast/ast.go" \\
&& ok "internal/ast/ast.go" \\
|| miss "missing critical file: internal/ast/ast.go"
test -f "internal/config/config.go" \\
&& ok "internal/config/config.go" \\
|| miss "missing critical file: internal/config/config.go"
test -f "internal/cache/cache.go" \\
&& ok "internal/cache/cache.go" \\
|| miss "missing critical file: internal/cache/cache.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 67 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~37d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/evanw/esbuild"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
esbuild is an extremely fast JavaScript/TypeScript bundler written in Go that compiles JavaScript, TypeScript, JSX, and CSS into optimized output for browsers. It achieves 10-100x performance improvements over webpack/Parcel by leveraging Go's concurrency and a custom parser, while providing built-in support for tree-shaking, minification, source maps, and ES modules without requiring a persistent cache. Hybrid Go/JavaScript monorepo: cmd/esbuild/ contains the Go CLI entrypoint and stdio protocol for inter-process communication; the service pattern (cmd/esbuild/service.go) allows spawning esbuild as a long-running daemon. TypeScript/JavaScript lives in compat-table/ (compatibility data generators) and bundled npm package distribution. Core bundling logic is implemented in Go (pkg/ directory not shown but inferred from .go file count of ~5.1M).
👥Who it's for
Frontend developers and framework maintainers (React, Vue, Svelte teams) who need sub-second builds during development and production-grade bundling without the performance overhead of webpack. Also appeals to tool authors building on top of bundlers, given esbuild's straightforward API for CLI, JavaScript, and Go.
🌱Maturity & risk
Production-ready and actively maintained. The project has multiple CHANGELOG files spanning 2020-2025, established CI/CD workflows (.github/workflows), a comprehensive plugin system, and detailed documentation. Recent activity visible across changelog entries through 2025 indicates ongoing development and stability.
Low risk of abandonment—single maintainer (Evan Wallace) with consistent multi-year commits. Dependency surface is small (caniuse-lite, @types/node) and focused. Main risk is that major architectural changes remain possible since it's a young (~5 years old) but opinionated tool; however, the API stability and plugin system are mature enough for production use.
Active areas of work
Active development on compatibility tables and documentation—the compat-table/ TypeScript subtree pulls from @mdn/browser-compat-data v7.3.9 and caniuse-lite v1.0.30001784, suggesting recent updates to CSS/JS feature compatibility tracking. The project maintains six dated changelogs through 2025, indicating ongoing releases and iterative improvements.
🚀Get running
Clone and build: git clone https://github.com/evanw/esbuild.git && cd esbuild && make. Requires Go (version specified in go.version). The Makefile orchestrates builds; check Makefile for available targets and RUNBOOK.md for detailed setup instructions.
Daily commands:
make to build; ./esbuild (or esbuild if installed globally via npm) to invoke. For development, check Makefile for test targets. The project is primarily CLI-driven; the service.go exposes a build service for programmatic use. See RUNBOOK.md for detailed dev workflow.
🗺️Map of the codebase
cmd/esbuild/main.go— Entry point for the esbuild CLI tool; orchestrates the bundling workflow and handles command-line arguments.internal/bundler/bundler.go— Core bundling logic that coordinates parsing, linking, and code generation; the heart of esbuild's fast bundling process.internal/ast/ast.go— Abstract syntax tree definitions for JavaScript and CSS; fundamental data structure used throughout parsing and transformation.internal/config/config.go— Configuration parsing and validation; defines all bundler options and build settings.internal/cache/cache.go— Caching layer for AST and filesystem operations; directly impacts bundler performance via memoization.go.mod— Go module definition; declares all external dependencies and Go version requirements.
🛠️How to make changes
Add a new JavaScript transformation
- Define the transformation logic in a new module under internal/ (
internal/bundler/bundler.go (add visitor method)) - Integrate the transformation into the bundler's AST processing pipeline (
internal/bundler/bundler.go (call from main bundling loop)) - Add configuration option to enable/disable the transformation (
internal/config/config.go (add field to BuildOptions)) - Write test cases covering the transformation behavior (
internal/bundler_tests/bundler_default_test.go (add test case))
Add support for a new CSS property
- Add the property to the CSS declaration table with metadata (name, value types, etc.) (
internal/css_ast/css_decl_table.go) - Update the CSS lexer if the property requires special tokenization (
internal/css_lexer/css_lexer.go (add token types if needed)) - Add compatibility data for the property from caniuse/MDN (
internal/compat/css_table.go) - Write CSS bundler tests to verify correct parsing and transformation (
internal/bundler_tests/bundler_css_test.go (add test case))
Add a new browser target or compatibility check
- Fetch compatibility data from caniuse-lite or MDN browser-compat-data (
compat-table/src/caniuse.ts or compat-table/src/mdn.ts) - Generate the compatibility table code with the build script (
compat-table/src/index.ts (regenerate js_table.ts and css_table.ts)) - Import and use the updated tables in the bundler's target resolution (
internal/compat/compat.go (call updated compat functions)) - Test target detection with new browser combinations (
internal/bundler_tests/bundler_default_test.go (add test with new target))
🔧Why these technologies
- Go — Native compilation to fast single binary; enables performance-critical bundling without JIT warmup; easy parallelization via goroutines.
- AST-based transformation — Enables precise code analysis and transformation for tree-shaking, splitting, and lowering; avoids regex-based brittle parsing.
- Caching (cache.go, cache_ast.go) — Avoids re-parsing and re-linking unchanged modules during watch/incremental builds; critical for developer experience.
- Compatibility tables (caniuse, MDN) — Enables automatic transpilation decisions based on target browsers; reduces manual babel configuration burden.
⚖️Trade-offs already made
-
Single-threaded bundler with parallel parsing
- Why: Simplifies linking and code generation phases which require global state; Go's goroutines handle parallelism within bounds.
- Consequence: Parsing is fast but linking may be bottleneck on very large codebases with many modules.
-
Built-in tree-shaking and splitting; no external graph library
- Why: Custom algorithms tuned for bundler semantics (ESM vs CommonJS, circular dependencies, dynamic imports).
- Consequence: More code to maintain but better performance and correctness than generic solutions.
-
Go-only implementation (no JavaScript plugin API initially)
- Why: Maximum performance and predictability; Go is compiled and controlled.
- Consequence: Plugins must be written in Go; limits ecosystem compared to webpack/Rollup; however esbuild now supports plugins via API.
-
CSS parsed into full AST with declaration tables
- Why: Enables property-aware lowering and autoprefixing; avoids string-based CSS manipulation.
- Consequence: Higher memory usage for CSS but more robust transformations and minification.
🚫Non-goals (don't propose these)
- Hot module replacement (HMR) — esbuild is a bundler, not a dev server; delegates HMR to external tools.
- Plugin ecosystem in JavaScript — esbuild plugins are Go-based for performance; no runtime plugin system.
- Package manager — does not resolve or install dependencies; relies on node_modules pre-existing.
- Runtime — esbuild produces bundles for browsers/Node.js; does not execute code.
🪤Traps & gotchas
No required environment variables noted, but go.version file specifies a pinned Go version—ensure local Go matches. The stdio_protocol.go suggests plugin communication expects strict message framing; malformed plugin messages can deadlock the bundler. The compat-table subtree uses a GitHub dependency (8f4179ffb5e7a06a12739400fcd31b5a34ef7964), not a npm package release—be aware when vendoring or in air-gapped builds. Makefile likely requires specific tools (possibly Go 1.18+, Node for tests); check Makefile comments.
🏗️Architecture
💡Concepts to learn
- AST (Abstract Syntax Tree) parsing — esbuild's core performance advantage comes from its hand-written Go parser that produces ASTs faster than V8 or other JS engines; understanding AST traversal is essential to contribute to bundling logic
- Tree shaking (dead code elimination) — One of esbuild's headline features; relies on ESM static analysis to remove unused exports, core to producing minimal bundles
- Module resolution (ESM vs CommonJS) — esbuild must handle both ESM import syntax and CommonJS require() at bundle time; the resolver is crucial for multi-format package support
- Code splitting & chunk management — esbuild supports dynamic imports and automatic chunk splitting for lazy loading; mentioned in README with example images (code-splitting-1.png, code-splitting-2.png)
- Stdio protocol for inter-process communication — esbuild's plugin system uses framed messages over stdin/stdout (cmd/esbuild/stdio_protocol.go) rather than in-process APIs, enabling language-agnostic plugin authorship
- Source maps (SourceMapV3 format) — esbuild generates source maps for debugging minified code; required for production builds and a key feature differentiator from older bundlers
- Minification & mangling — esbuild includes a built-in minifier (not delegated to terser), reducing bundle size and build time; core optimization pass in the bundler pipeline
🔗Related repos
webpack/webpack— The primary performance target and feature-parity competitor; webpack dominates enterprise builds and esbuild aims to be a faster, simpler alternativeparcel-bundler/parcel— Another zero-config bundler attempting to simplify developer experience; esbuild's speed advantage is a direct response to Parcel's slower build timesswc-project/swc— Rust-based JavaScript transformer with similar performance philosophy; shares esbuild's goal of replacing slower JavaScript tooling with compiled languagesvitejs/vite— Modern build tool and dev server that often uses esbuild as its dependency pre-bundler in package.json, making it a primary consumer of esbuildmdn/browser-compat-data— Upstream source of browser compatibility data consumed by esbuild's compat-table tooling for generating feature matrices
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test suite for CSS bundling edge cases in bundler_css_test.go
The repo has internal/bundler_tests/bundler_css_test.go but given esbuild's focus on speed and the complexity of CSS handling (separate from JS), there are likely edge cases around CSS imports, media queries, nested selectors, and CSS-in-JS that lack coverage. This directly impacts build correctness for a major use case.
- [ ] Review existing bundler_css_test.go to identify tested scenarios
- [ ] Add tests for CSS @import cycles and resolution
- [ ] Add tests for CSS modules with scoped names across split chunks
- [ ] Add tests for mixed CSS/JS imports in code-split bundles (referencing bundler_splitting_test.go patterns)
- [ ] Add tests for CSS within loader transformations (cross-reference bundler_loader_test.go)
- [ ] Run 'make test' to validate and ensure no regressions
Implement CI workflow for compat-table validation and browser compatibility checks
The repo has a compat-table/ directory with TypeScript sources for generating compatibility tables from caniuse-lite and @mdn/browser-compat-data, but .github/workflows/ (validate.yml, ci.yml, e2e.yml, publish.yml) appear to lack a dedicated step. This should automatically regenerate and validate compat-table outputs on dependency updates.
- [ ] Create .github/workflows/compat-table.yml workflow
- [ ] Add step to run 'npm install' in compat-table/ directory
- [ ] Add step to build compat-table TypeScript (tsconfig.json exists) and run src/index.ts
- [ ] Add step to validate generated tables match expected output format
- [ ] Configure workflow to trigger on changes to compat-table/src/, go.mod (browser support changes), and dependency PRs
- [ ] Document in docs/development.md how to manually regenerate compatibility tables
Add integration tests for import phase annotations in bundler_importphase_test.go
The file bundler_importphase_test.go exists but import phase (e.g., 'with' assertions, phase flags in ES module syntax) is an emerging spec feature. Given esbuild's goal to support modern JavaScript, this test file likely needs expansion for edge cases like circular dependencies with phased imports, bundling with import assertions, and cross-file phase resolution.
- [ ] Review existing bundler_importphase_test.go test coverage and TC39 import assertions spec
- [ ] Add tests for import assertions (JSON/WASM assertions) in bundled output
- [ ] Add tests for interaction between import phases and tree-shaking (reference bundler_dce_test.go patterns)
- [ ] Add tests for import phases across code-split boundaries
- [ ] Add tests for phase conflicts in circular dependencies
- [ ] Verify tests pass with 'make test' and update CHANGELOG-2025.md if new features are validated
🌿Good first issues
- Add TypeScript definitions for the stdio protocol in compat-table/src/types.d.ts to improve plugin author developer experience when writing esbuild plugins in TypeScript.
- Expand compat-table/src/index.ts to cover additional CSS features (e.g., container queries, :has() selector) by mapping new caniuse-lite data, since only js_table.ts and css_table.ts currently exist.
- Document common plugin pitfalls in RUNBOOK.md by analyzing cmd/esbuild/stdio_protocol.go deadlock scenarios and adding troubleshooting examples, since the protocol is powerful but easy to misuse.
⭐Top contributors
Click to expand
Top contributors
- @evanw — 93 commits
- @2767mr — 1 commits
- @cuiweixie — 1 commits
- @MikeWillCook — 1 commits
- @BPJEnnova — 1 commits
📝Recent commits
Click to expand
Recent commits
6a794df— publish 0.28.0 to npm (evanw)64ee0ea— fix #4435: supportwith { type: text }imports (evanw)ef65aee— fix sort order insnapshots_packagejson.txt(evanw)1a26a8e— try to fixtest-old-ts, also shuffle CI tasks (evanw)556ce6c— use''instead ofnullto omit build hashes (evanw)8e675a8— ci: allow missing binary hashes for tests (evanw)7067763— Reapply "update go 1.25.7 => 1.26.1" (evanw)39473a9— fix #4343: integrity check for binary download (evanw)2025c9f— publish 0.27.7 to npm (evanw)c6b586e— fix typo inMakefilefor@esbuild/win32-x64(evanw)
🔒Security observations
The esbuild repository demonstrates a reasonable security posture as a well-maintained open-source project. The codebase is written primarily in Go with some TypeScript/JavaScript components. No critical vulnerabilities were identified in the provided file structure and dependencies. However, there are opportunities for improvement: (1) implementing automated dependency scanning in CI/CD pipelines, (2) establishing a formal security disclosure process via SECURITY.md, (3) regularly updating and monitoring external dependencies, and (4) verifying GitHub dependency pinning mechanisms. The absence of hardcoded secrets, SQL injection risks, or obvious injection vulnerabilities is positive. For a bundler tool that processes user code, maintaining strong dependency hygiene is especially important to prevent supply chain attacks.
- Medium · Outdated Browser Compatibility Data Dependency —
package.json - dependencies/@mdn/browser-compat-data. The @mdn/browser-compat-data dependency version 7.3.9 may be outdated. Compatibility data packages should be regularly updated to ensure accurate browser support information and to receive any security patches or corrections. Fix: Regularly update @mdn/browser-compat-data to the latest version. Run 'npm audit' and 'npm outdated' to check for available updates and vulnerabilities. - Medium · Pinned GitHub Dependency Without Verification —
package.json - githubDependencies/compat-table/compat-table. The compat-table dependency is pinned to a specific GitHub commit (8f4179ffb5e7a06a12739400fcd31b5a34ef7964) without clear verification mechanisms. This approach may introduce supply chain risks if the commit hash is not regularly verified or if the repository is compromised. Fix: Implement dependency verification by: 1) Adding commit signature verification, 2) Using package lock files with integrity hashes, 3) Regularly auditing external dependencies, 4) Consider using private registries or mirrors for critical dependencies. - Low · Missing Security Configuration Files —
Repository root. No security-related configuration files detected (e.g., .snyk, .dependabot, security.md, SECURITY.md). These files help coordinate vulnerability disclosures and automate dependency updates. Fix: Create a SECURITY.md file documenting vulnerability disclosure process. Enable Dependabot in GitHub settings for automated dependency update PRs and vulnerability alerts. - Low · No Evidence of Dependency Scanning in CI/CD —
.github/workflows/ci.yml, validate.yml. While GitHub Actions workflows exist (.github/workflows/), there is no explicit evidence of automated dependency vulnerability scanning (e.g., npm audit, Snyk, or similar tools in CI pipeline). Fix: Add 'npm audit' or equivalent dependency scanning to the CI/CD pipeline to catch vulnerable dependencies before merging. Include this in the validate.yml or create a dedicated security scan workflow. - Low · Go Module Dependency Management Not Fully Assessed —
go.mod, go.sum. The go.mod and go.sum files are present but their content was not provided for analysis. Go dependencies could potentially contain vulnerabilities that require assessment. Fix: Run 'go list -json -m all | nancy sleuth' or 'go audit' (with appropriate tools) to scan Go dependencies for known vulnerabilities. Ensure go.sum is committed to version control for integrity verification.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.