Skip to main content
ASoc
Comparison

esbuild vs. Vite: What This Repo's Own Lockfile Says

Neither is a dependency here — but the Vite version vitest pulls in has already dropped esbuild for Rolldown, proven straight from the lockfile.

The ASoc Team8 min read

esbuild is a Go-based JavaScript/TypeScript bundler and minifier built for raw transform speed; Vite is a dev server plus build tool that historically used esbuild internally for dependency pre-bundling while handing the production bundle to Rollup. Use esbuild directly for a library, a CLI, or a step inside a larger pipeline; use Vite for an application that needs a dev server, HMR, and a plugin ecosystem. This repository depends on neither directly — but the version of Vite it does pull in, transitively, has already stopped using esbuild at all.

Neither is a direct dependency

$ cat package.json | grep -E '"(vite|esbuild)"'
$ echo $?
1

No match, in either dependencies or devDependencies. This storefront runs on Next.js with Turbopack as its build engine — the same "the framework owns the build" situation covered for Webpack in Vite vs. Webpack, and the reason Vite vs. Vue is a layer confusion rather than a comparison: the build tool and the component model are separate choices, and a framework usually makes one of them for you. But vitest (the test runner behind npm test, listed as a direct devDependency) pulls in Vite as one of its own dependencies, which means Vite's actual dependency tree — not a hypothetical one — is sitting in this repository's lockfile right now.

What that lockfile entry says

$ node -e "console.log(require('./package-lock.json').packages['node_modules/vite'].version)"
8.1.3

Vite 8.1.3, pulled in by vitest@4.1.9. And its own dependency list, straight from the same lockfile:

"node_modules/vite": {
  "version": "8.1.3",
  "dependencies": {
    "lightningcss": "^1.32.0",
    "picomatch": "^4.0.4",
    "postcss": "^8.5.16",
    "rolldown": "~1.1.3",
    "tinyglobby": "^0.2.17"
  },
  "peerDependencies": {
    "esbuild": "^0.27.0 || ^0.28.0"
  },
  "peerDependenciesMeta": {
    "esbuild": { "optional": true }
  }
}

rolldown is a hard dependency. esbuild is listed only as an optional peer dependency — Vite declares it can use one if the host project provides it, but doesn't install it, doesn't require it, and doesn't fall back to it for anything mandatory. Checking what's actually on disk confirms it:

$ grep -c '"@esbuild/' package-lock.json
0
$ grep -c '"node_modules/@rolldown/' package-lock.json
18

Zero esbuild platform binaries anywhere in this tree. Sixteen distinct @rolldown/binding-* native packages listed in the lockfile instead — one per target platform (Linux, macOS, Windows, even wasm32-wasi as a portable fallback) — the same shape npm uses to ship any Rust/Go-native tool across operating systems. Most "esbuild vs. Vite" articles describe Vite as esbuild-plus-Rollup, because that was true for years and is still true of older Vite majors. It stopped being true here: this repository's own lockfile shows Vite 8 has already completed the move to Rolldown — a Rust rewrite of Rollup with a compatible plugin API — as its actual bundler, with esbuild demoted to an integration point a consuming project can opt into, not a piece Vite ships itself.

What each one still does, on its own terms

esbuildVite (pre-8, historical)Vite 8 (measured here)
Primary jobBundle/transform/minify, directlyDev server + build orchestratorDev server + build orchestrator
Dependency pre-bundlingesbuildRolldown
Production bundleesbuild itself, if you call it as a bundlerRollupRolldown
Written inGoJS (orchestration)JS (orchestration)
Bundler engine languageGoGo (esbuild) + JS (Rollup)Rust (Rolldown)
Typical useA library, a CLI, one step of a custom pipelineA standalone app (React, Vue, Svelte) with dev server + HMRSame, engine swapped underneath
Config fileNone required — usable via API or CLI flagsvite.config.tsvite.config.ts
Appears in this repoNot at allNot at all, directlyTransitively, via vitest

The row that answers "which do I pick" for most readers is "typical use": esbuild is a tool you reach for directly when you're building something small and want raw speed with minimal ceremony; Vite is what you reach for when you want a full application dev experience and don't want to hand-assemble one from esbuild plus a dev server plus HMR plus a plugin system. They aren't really competitors at the layer most comparison posts frame them at — Vite used esbuild, the way this repo's own lockfile makes visible for one specific, real dependency.

Why this matters beyond trivia

Two migrations that used to be routine — "upgrade Vite" and "add an esbuild-based tool as a peer" — now interact differently than the always-esbuild-inside story implies:

  • Upgrading vitest to a version pulling Vite 8+ no longer guarantees an esbuild binary lands in node_modules. A tool in your own pipeline that assumed esbuild would be present transitively (because Vite always pulled it in) can silently stop finding it. This repo's scripts/seo/ and scripts/release/ tooling never made that assumption — they're described in their own documentation as "plain node, zero dependencies," which is exactly the posture that survives a change like this without noticing it happened.
  • The peer-dependency line is the actual opt-in point now. If a project wants esbuild-specific behavior alongside Vite 8 — a plugin that shells out to esbuild's API directly, say — it has to add esbuild as its own dependency; Vite will use it if present (the peer dependency is satisfied) but will not go fetch it on the project's behalf.

Neither point changes anything this repository has to do today — nothing here calls esbuild's API directly, and vitest doesn't need it satisfied for the test suite to run. It's the kind of fact that matters the next time a npm test starts throwing an unfamiliar peer-dependency warning after a routine npm update, and the instinct is to assume the lockfile is broken rather than that a transitive tool's own architecture moved.

Troubleshooting

SymptomCauseFix
A plugin or tool expects an esbuild binary that isn't in node_modulesVite 8+ made esbuild an optional peer dependency instead of a hard oneAdd esbuild as a direct dependency of your own project if something in your pipeline calls its API
An old blog post or doc says "Vite uses esbuild for pre-bundling" and it doesn't match what you seeTrue for Vite's earlier major versions; Vite 8 moved dependency pre-bundling to RolldownCheck your actual installed Vite version's own package.json/lockfile entry rather than trusting a general description
npm ls esbuild returns nothing even though vite is installedExpected on Vite 8+ — esbuild is no longer a transitive dependencyNot a bug; install esbuild explicitly if you need it
Confusing "esbuild vs. Vite" with "esbuild vs. Webpack"The former is a library/tool vs. an app dev-server-plus-bundler; the latter is two full bundlersFrame the choice by what you're building (a library → esbuild candidates; an app → Vite/Webpack/framework-owned)
Assuming your framework's dev server behaves like standalone ViteA framework (Next.js, SvelteKit) that bundles Vite internally can pin its own version and configuration, diverging from the standalone CLI defaultsCheck the framework's own docs for which bundler version and config it actually wires up

Frequently asked questions

If this codebase doesn't use Vite directly, why does it show up in the lockfile at all? vitest, this repo's test runner (npm test), depends on Vite internally to power its module transforms and watch mode — the same way next depends on its own bundling internals without a project needing to configure them separately. Vite ends up in node_modules as a consequence of choosing vitest, not as a project-level decision.

Does Vite still use Rollup at all in version 8? Not according to this repository's own lockfile entry — Rolldown, a Rust-based Rollup-compatible rewrite, is the dependency listed, and Rollup itself doesn't appear as a node_modules/vite dependency. Rolldown is designed to be close enough to Rollup's plugin API that most Rollup plugins are expected to keep working, but the underlying engine has changed.

Should I install esbuild myself if I'm using Vite 8? Only if something in your own toolchain calls esbuild's API directly — a custom script, a plugin that isn't Vite-native. If your usage is "write Vite config, run vite build," Vite's own bundling no longer touches esbuild at all in this version, so there's nothing to add.

Is Rolldown the same as Turbopack, the bundler this repository's own build actually uses? No — different projects, different languages sharing only "written in Rust, aimed at Rollup/webpack-class problems." Turbopack is Vercel's bundler, built into Next.js and used by this repo's own next build; Rolldown is the Vite team's Rollup-compatible rewrite, arriving here only as a transitive dependency of vitest, never invoked by this repo's actual production build.

Templates in this post

ASoc Till (a POS-system landing page), ASoc Timbre (an AI voice-generator marketing site) and ASoc Uptime (a web-hosting landing page) all build the same way this storefront does — no vite.config.ts, no esbuild in dependencies, the framework's own bundler doing the work.

Browse the full sets: Next.js landing page templates, Tailwind landing page templates. For the framework-owns-the-build case worked through in full, see Vite vs. Webpack; for what this repo's own build actually ships, Next.js Bundle Analyzer.

Keep reading

Comparison11 min read

Gumroad Alternative: The Six Jobs You Take Back In-House

A hosted storefront does six jobs. Another one changes the fee; owning your storefront takes them back as code — 1,607 lines here, file by file.

Read more