Why JavaScript Developers Are Moving to Rust-Based Tools
TL;DR
Developers aren't learning Rust — they're using tools written in Rust. The distinction matters. You don't need to know Rust to use SWC, Biome, Turbopack, or Rspack. You just install an npm package, and suddenly your builds are 10x faster. The adoption pattern is pragmatic: when a Rust tool reaches API parity with its JS predecessor and the migration path is < 1 hour, teams switch. That threshold has been crossed for transpilation, formatting, and linting in 2026.
Key Takeaways
- Speed is the gateway drug — 10-100x faster feedback loops justify the switch
- Migration cost matters — Tools with JS-compatible APIs win (Biome ≈ ESLint, Rspack ≈ Webpack)
- The "no config" advantage — Biome replaces two configs with one; tsx replaces ts-node configs
- Not a rewrite — Most teams adopt Rust tools incrementally, one tool at a time
- Rule parity is the blocker — Teams hold back when the Rust tool lacks rules they depend on
The Adoption Pattern
How teams actually switch to Rust-based tools:
Stage 1: The Slow Build Problem
Every team hits this. CI takes 5 minutes. Local build takes 30 seconds. Nobody talks about it; everyone hates it.
# A typical pre-Rust CI pipeline:
lint (ESLint + Prettier): ~45s
type-check (tsc): ~25s
test (Jest): ~90s
build (Webpack): ~180s
Total: ~340s (~6 minutes)
# Post-Rust CI pipeline:
lint (Biome): ~2s
type-check (tsc --noEmit): ~22s # tsc has no Rust replacement
test (Vitest): ~40s
build (Turbopack/esbuild): ~30s
Total: ~94s (~1.5 minutes)
The CI speed win is what opens the conversation.
Stage 2: The Gateway Tool (Usually Formatting)
Prettier → Biome is the most common entry point. The motivation: formatting is 100% mechanical. There's no linting philosophy, no team debate. It just formats code. When Biome formats identically to Prettier and runs 30x faster, the migration is a no-brainer.
# Migration path: Prettier → Biome
# 1. Install Biome
npm install --save-dev @biomejs/biome
# 2. Generate biome.json from .prettierrc
npx @biomejs/biome migrate prettier --write
# 3. Replace scripts
# "format": "prettier --write ." → "format": "biome format --write ."
# 4. Remove Prettier
npm uninstall prettier
# Time: ~20 minutes
# Risk: Very low (formatting is non-breaking)
Stage 3: Bundler Migration
After formatting, teams often look at build speed. The pattern here is more risk-sensitive:
Vite path:
- New React/Vue projects: Start with Vite
- Existing Webpack: Consider if webpack-specific plugins are blocking
Rspack path:
- Existing Webpack: Same config, Rust speed
- Good for: large apps (1000+ modules) where Webpack is slow
- Not good for: small apps already fast enough
Turbopack path:
- Next.js users: Already have it
- Zero migration cost — it's the default in Next.js 15
Where the Resistance Comes From
Not every team switches, and the reasons are worth understanding:
1. ESLint Plugin Ecosystem
// Teams stay on ESLint for specific plugin coverage:
// eslint-plugin-react-hooks — critical for React
// eslint-plugin-jsx-a11y — accessibility rules
// @tanstack/eslint-plugin-query — TanStack Query rules
// eslint-plugin-import — import ordering, missing deps
// @typescript-eslint — advanced TypeScript rules
// Biome's coverage in 2026:
// ✅ ~300 rules (vs ESLint's ~700+ across plugins)
// ⚠️ No React hooks plugin equivalent yet
// ⚠️ No import plugin equivalent yet
// ✅ No config complexity (one file)
The compromise many teams use:
// Use Biome for formatting + basic linting
// Keep ESLint for framework-specific rules only
// package.json
{
"scripts": {
"format": "biome format --write .",
"lint": "eslint src/ --ext .ts,.tsx", // Only for React hooks etc.
"check": "biome check . && eslint src/"
}
}
2. Native Addon Compatibility
Some packages use Node.js native addons (.node files compiled from C++). These target V8 specifically and may not work on Bun's JSC or require recompilation for ARM vs x86.
3. "Good enough" Problem
For small projects, a 2-second lint step doesn't need to become a 20ms lint step. The investment in migration isn't worth the gain.
The Technical Reason Rust Won
JavaScript tooling in Rust has three concrete advantages:
1. Parallelism
Node.js: event loop, single-threaded JS, worker threads for parallelism
Rust: native threads, no GIL, shares memory safely via ownership system
Result: Biome can analyze 1000 files simultaneously in native threads
ESLint runs rules mostly single-threaded (worker_threads helps but overhead exists)
2. Zero-copy parsing
Typical JS parser (acorn, babylon):
String → char[] → AST nodes (heap allocations per node)
Rust AST (SWC, oxc):
String → AST backed by arena allocator
Thousands of nodes in one allocation
Cache-friendly, no GC pressure
3. AOT compilation
JavaScript tools: JIT compiled at runtime, warm-up time exists
Rust tools: compiled to native machine code, immediate peak performance
The Practical Migration Roadmap
For a team ready to move:
Week 1: Formatting
- Replace Prettier with Biome formatter
- ~20 min migration, zero risk
- Win: 30x faster formatting, fewer deps
Week 2-3: Linting (partial)
- Add Biome linting rules
- Keep ESLint only for rules Biome doesn't have
- Win: 80% of lint runs faster
Month 2: Bundler (if appropriate)
- Next.js: Already on Turbopack, no action
- Vite users: Already fast enough (Vite dev = ESM, no bundle)
- Webpack users: Evaluate Rspack migration
Ongoing: Test runner
- Migrate from Jest → Vitest (1-2 hours, worth it for ESM support alone)
Tools That Don't Have Rust Replacements Yet
Not everything has moved to Rust:
| Tool | Status in 2026 |
|---|---|
| TypeScript type checking (tsc) | No Rust alternative — too complex |
| Babel plugins (custom transforms) | Stay on Babel if using custom plugins |
| Webpack custom loaders | Rspack supports most; some need updates |
| ESLint framework plugins | No Biome equivalent for react-hooks etc. |
| Prettier plugins (MDX, etc.) | Biome supports some but not all |
The rule: Rust tools win on the generic cases. Custom/niche tooling stays in JavaScript.
Compare Rust vs JS tooling package health on PkgPulse.
See the live comparison
View biome vs. eslint on PkgPulse →