Oxlint vs ESLint: Rust-Powered Linting Performance 2026
·PkgPulse Team
TL;DR
Oxlint is 50-100x faster than ESLint and ready for production — but as a complement, not a replacement. It runs first as a fast pass catching common errors (500+ rules), then ESLint handles TypeScript-aware rules and plugins that Oxlint doesn't support yet. The Vercel team runs both in CI: oxlint in < 1 second, ESLint in parallel only for the rules oxlint misses. For solo TypeScript projects, oxlint + ESLint is the performance-optimal stack in 2026.
Key Takeaways
- Oxlint: ~400K downloads/week, written in Rust (via oxc), 500+ rules, ~1s on large codebases
- ESLint: 30M downloads/week, ecosystem standard, TypeScript-aware rules, full plugin system
- Speed: Oxlint is 50-100x faster than ESLint on the same rules
- Coverage: Oxlint covers ~50-60% of what most projects need from ESLint
- Strategy: Run oxlint as fast pre-check, ESLint for type-aware rules only
- No plugins: Oxlint doesn't support custom plugins (yet) — ecosystem rules (Tailwind, a11y) still need ESLint
Downloads
| Package | Weekly Downloads | Trend |
|---|---|---|
eslint | ~30M | → Stable |
oxlint | ~400K | ↑ Fast growing |
@biomejs/biome | ~1.2M | ↑ Growing |
Oxlint: Setup and Rules
npm install --save-dev oxlint
// package.json — run oxlint first:
{
"scripts": {
"lint": "oxlint --deny-warnings && eslint --max-warnings 0 ."
}
}
// oxlintrc.json (optional — oxlint has good defaults):
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"rules": {
// Correctness (errors):
"no-unused-vars": "error",
"no-undef": "error",
"eqeqeq": "error",
"no-debugger": "error",
// React rules (built-in, no plugin needed):
"react/jsx-key": "error",
"react/no-danger": "warn",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
// TypeScript rules (built-in):
"typescript/no-explicit-any": "warn",
"typescript/no-unused-vars": "error",
// Unicorn-style rules (subset):
"unicorn/prefer-array-flat-map": "warn",
"unicorn/prefer-string-trim-start-end": "warn"
},
"plugins": ["react", "react-hooks", "typescript", "unicorn"],
"env": {
"browser": true,
"node": true,
"es2022": true
}
}
Speed Benchmark
Next.js project: 1200 TypeScript files, 85K lines
ESLint (with typescript-eslint, react, import):
Cold run: ~45s
Warm run: ~38s
Oxlint (equivalent rules):
Cold run: 0.4s
Warm run: 0.4s (Rust, no JS startup)
ESLint (minimal — type-aware rules only, no react/import):
Cold run: 12s
Warm run: 8s
Optimal combo:
oxlint: 0.4s (catches 60% of issues instantly)
eslint-minimal: 8s (only type-aware rules in parallel)
Total effective: 8s (parallel) vs 38s ESLint-only
What Oxlint Covers vs What It Doesn't
✅ Oxlint has built-in:
- Core JavaScript rules (no-unused-vars, eqeqeq, etc.)
- React + React Hooks rules
- TypeScript basic rules
- Subset of unicorn rules
- Import/export validation (basic)
- Performance anti-patterns
❌ Still needs ESLint:
- Type-aware TypeScript rules (@typescript-eslint with type-checking)
e.g., @typescript-eslint/await-thenable
@typescript-eslint/no-floating-promises
@typescript-eslint/no-misused-promises
- eslint-plugin-tailwindcss (class sorting)
- eslint-plugin-jsx-a11y (accessibility)
- Custom organization rules
- eslint-plugin-import (advanced cycle detection)
- Security rules
Optimal ESLint Config (Paired with Oxlint)
When using oxlint as the primary linter, reduce ESLint to only what it does uniquely well:
// eslint.config.js — minimal, only type-aware rules + plugins:
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import tailwindPlugin from 'eslint-plugin-tailwindcss';
import a11y from 'eslint-plugin-jsx-a11y';
import prettierConfig from 'eslint-config-prettier';
export default [
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parser: tsParser,
parserOptions: {
project: './tsconfig.json', // Required for type-aware rules
tsconfigRootDir: import.meta.dirname,
},
},
plugins: { '@typescript-eslint': tsPlugin },
rules: {
// Only type-aware rules that oxlint can't do:
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
'@typescript-eslint/strict-boolean-expressions': 'warn',
},
},
{
plugins: {
tailwindcss: tailwindPlugin,
'jsx-a11y': a11y,
},
rules: {
'tailwindcss/classnames-order': 'warn',
...a11y.configs.recommended.rules,
},
},
prettierConfig,
];
Pre-commit Hook (husky + lint-staged)
// .lintstagedrc.json:
{
"*.{ts,tsx,js,jsx}": [
"oxlint", // Fast: runs in ~200ms on changed files
"eslint --fix" // Slower: only type-aware + plugin rules
],
"*.{ts,tsx,js,jsx,json,md,css}": ["prettier --write"]
}
Comparison Table
| Oxlint | ESLint | Biome | |
|---|---|---|---|
| Speed | 50-100x faster | Baseline | 25x faster |
| Rule count | 500+ | 10,000+ (w/ plugins) | 300+ |
| Plugin system | ❌ (planned) | ✅ Full ecosystem | ❌ |
| Type-aware rules | ❌ | ✅ | ❌ |
| TypeScript formatting | ❌ | via Prettier | ✅ |
| Tailwind sorting | ❌ | ✅ (plugin) | ❌ |
| Maturity | 2023/growing | 2013/mature | 2023/growing |
Decision Guide
Use Oxlint if:
→ CI lint times are painful (>30s on ESLint)
→ Running oxlint as a first-pass alongside ESLint
→ New project comfortable with cutting-edge tools
Keep ESLint-only if:
→ Need full plugin ecosystem without hybrid complexity
→ Team unfamiliar with multi-linter setup
→ Custom rules or plugins are required
Optimal stack for TypeScript projects:
oxlint + minimal ESLint (type-aware) + Prettier
→ Fast feedback: oxlint in <1s
→ Comprehensive: ESLint for type-aware rules
→ Formatting: Prettier (or Biome if no Tailwind sorting needed)
Compare oxlint and ESLint package health on PkgPulse.