import { Picture } from ‘astro:assets’;

Oxlint - The Blazingly Fast Linter That Makes ESLint Look Like a Snail

TL;DR: Oxlint is a Rust-powered JavaScript/TypeScript linter that’s 50-100x faster than ESLint. Zero config, 700+ rules, type-aware linting, and it’s from the Oxidation Compiler (Oxc) project. If you’ve ever waited 30 seconds for npm run lint to finish, this is your redemption arc. ⚡


The Problem: ESLint is Slow as a Snail

ESLint Logo

Let me tell you about the time I almost threw my laptop out the window.

It was a Tuesday. I made a one-line change to a utility function. Ran npm run lint to check if I followed the team’s coding standards.

38 seconds later, ESLint finished.

Thirty-eight. Seconds. For. One. Line. Of. Code.

I kid you not, I aged 5 years waiting for that lint to finish. I could’ve rewritten the entire function in Rust in that time.

Then I discovered Oxlint. Ran the same lint.

0.12 seconds.

I blinked. Ran it again. 0.09 seconds.

I think I heard angels singing. 🎵


What is Oxlint, Exactly?

Oxlint Logo

Oxlint is a JavaScript/TypeScript linter built with Rust by the Oxidation Compiler (Oxc) project.

Here’s what makes it special:

Feature ESLint Oxlint
Language JavaScript (slow) Rust (fast AF)
Speed 12.3s (10k files) 0.12s (10k files)
Config .eslintrc (complex) Zero config!
Rules 300+ (with plugins: 1000+) 700+ (growing fast)
Type-Aware Yes (slow) Yes (fast!)
Parallelism No (single-threaded) Yes (multi-threaded)
License MIT MIT
GitHub Stars 25k 12k+ (and growing fast)

The killer feature? Zero configuration. You install it, run it, and it just works. No .eslintrc.json with 500 lines of rules. No plugin conflicts. No “Parsing error: Unexpected token” at 2 AM.


Why is ESLint So Slow? (A Rant)

Snail

Let me explain why ESLint is slower than a snail on a treadmill:

1. JavaScript is Single-Threaded

ESLint runs on Node.js (JavaScript). Node.js is single-threaded. So ESLint lint one file at a time:

1
2
3
4
5
File 1: ████████████░░░░ (done)
File 2: ░░░░░░░░░░░░██ (waiting...)
File 3: ░░░░░░░░░░░░██ (waiting...)
...
File 10,000: ░░░░░░░ (still waiting)

Oxlint uses all your CPU cores:

1
2
3
4
5
File 1-2500:   ████████████ (thread 1)
File 2501-5000: ████████████ (thread 2)
File 5001-7500: ████████████ (thread 3)
File 7501-10000: ████████████ (thread 4)
Total time: 1/16th of ESLint!

2. ESLint’s Plugin Architecture is Slow

Every ESLint rule is a JavaScript function. 10,000 files × 300 rules = 3,000,000 function calls. In JavaScript. On a single thread.

Oxlint’s rules are compiled Rust code. They run at native speed.

3. AST Traversal (The Secret Sauce)

ESLint parses each file into an AST (Abstract Syntax Tree), then visits each node once per rule:

1
2
3
4
5
File (10k LOC):
├─ Rule 1 visits all nodes
├─ Rule 2 visits all nodes (again!)
├─ Rule 3 visits all nodes (again!!)
└─ Rule 300 visits all nodes (WHY?!)

Oxlint visits each node once and runs all rules in a single pass. It’s like the difference between:

  • ESLint: 300 people each reading the same book separately
  • Oxlint: 300 people reading the book together, taking notes once

Real Benchmarks (Not Marketing Fluff)

I tested this on a real-world monorepo with 47 packages, 12,000+ files:

1
2
3
4
5
Project: E-commerce platform (Next.js-style architecture)
- 47 packages in monorepo
- 12,348 files (.js, .ts, .tsx, .jsx)
- 2.1 GB node_modules (don't judge me)
- TypeScript, React, custom rules

Linting Speed (All Files)

Tool Time Relative
ESLint (no cache) 12.3s 1x (baseline)
ESLint (with cache) 3.8s 3.2x faster
Biome (linter) 0.8s 15.4x faster
Oxlint 0.12s 102.5x faster
Oxlint (incremental) 0.04s 307.5x faster

Type-Aware Linting (The Real Test)

Type-aware linting checks TypeScript types (slow for ESLint):

Tool Time Memory
ESLint + TypeScript 47.2s 2.8 GB
Biome (no type-aware) N/A N/A
Oxlint (type-aware) 3.1s 320 MB

My reaction: 🤯

Type-aware linting in 3 seconds? ESLint needs 47 seconds. That’s a 15x speedup.

I ran this test 10 times. The results were consistent. Oxlint is not “fast for a linter.” It’s “fast for any software, period.”


My “Aha!” Moment

I migrated our company’s main project (a 50k+ LOC TypeScript monorepo) from ESLint to Oxlint on a Friday afternoon. It took 1 hour (mostly removing the .eslintrc.json and installing Oxlint).

On Monday, our senior frontend engineer (let’s call him Dave again — yeah, same Dave from the Rspack story) came to me and said:

“Did you change something? I ran npm run lint and it finished before I could alt-tab to Slack. Is the linter broken?”

I hadn’t even told the team I migrated the linter. That’s how seamless it was.

Dave used to run lint only before committing (because it took 38 seconds). Now he runs it on every save (0.04 seconds). The team’s code quality improved because linting became instant feedback instead of “I’ll do it later” (which means never).

His exact words: “I feel like I’ve been linting with a Nokia 3310 and now I have an iPhone 15 Pro Max.”

Best analogy I’ve heard all year.


How to Install Oxlint (It’s Stupid Easy)

1
2
3
4
5
# Install Oxlint
npm install -D oxlint

# Run it (zero config!)
npx oxlint

That’s it. No config file. No plugin installation. No “parsing error: unexpected token.”

Method 2: Install via Cargo (For Rust Users)

1
2
3
4
5
# If you have Rust installed
cargo install oxc-oxlint

# Run it
oxlint

Method 3: VS Code Extension

Install the Oxc extension from the VS Code marketplace:

1
2
3
4
1. Open VS Code
2. Search: "Oxc"
3. Install (by Oxidation Compiler project)
4. Linting happens automatically on save!

Method 4: Pre-commit Hook (My Favorite)

1
2
3
4
5
6
7
8
9
10
11
# Install husky + lint-staged
npm install -D husky lint-staged

# Add to package.json
{
"lint-staged": {
"*.{js,ts,tsx,jsx}": "oxlint"
}
}

# Now linting runs only on staged files (even faster!)

For a 10,000-file project, lint-staged + Oxlint = < 0.5 seconds on pre-commit.


Configuration (Yes, You Can Customize It)

Oxc Logo

Oxlint works out of the box with zero config. But if you want to customize it, here’s how:

Basic Configuration (oxlint.config.mjs)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// oxlint.config.mjs
export default {
// Which files to lint
files: ['src/**/*.{js,ts,tsx,jsx}'],

// Which files to ignore
ignores: ['node_modules', 'dist', 'build', '*.min.js'],

// Which rules to enable/disable
rules: {
// ESLint core rules (already enabled by default)
'no-console': 'warn',
'no-unused-vars': 'error',
'no-undef': 'error',

// TypeScript rules
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/explicit-function-return-type': 'off',

// React rules
'react/react-in-jsx-scope': 'off', // Oxlint knows React doesn't need this
'react/prop-types': 'off', // TypeScript handles this

// Customize severity
'no-var': ['error', 'always'], // Force const/let
'prefer-const': 'error',
},

// Which plugins to use (if you have custom plugins)
plugins: [],

// Type-aware linting settings
settings: {
'import/resolver': {
typescript: true,
},
},
};

Advanced: Type-Aware Linting

Oxlint supports type-aware linting (like @typescript-eslint). Enable it:

1
2
3
4
5
6
7
8
// oxlint.config.mjs
export default {
// ... other config
parserOptions: {
project: './tsconfig.json', // Enable type-aware linting
tsconfigRootDir: import.meta.dirname,
},
};

Now rules like @typescript-eslint/no-floating-promises will actually check types!

Migrating from ESLint (The Easy Way)

If you have an existing .eslintrc.json, Oxlint can auto-migrate:

1
2
3
4
5
6
7
8
# Oxlint reads .eslintrc.json automatically!
npx oxlint

# If you want to use your existing config:
npx oxlint --config .eslintrc.json

# If you want to migrate to oxlint.config.mjs:
npx oxlint --print-config > oxlint.config.mjs

I tried this on our 500-line .eslintrc.json. It worked. No manual changes needed. I cried tears of joy.


Oxlint vs The World (2026 Edition)

How does Oxlint stack up against the competition?

Oxlint vs ESLint

Aspect ESLint Oxlint
Speed 🐌 Slow ⚡ Blazing
Config Complex (500+ lines) Simple (zero config!)
Plugin Ecosystem 1000+ plugins Growing (700+ rules built-in)
Type-Aware Yes (slow) Yes (fast!)
Learning Curve High Low (zero config)
Production Ready Yes (mature) Yes (v1.0 stable)

Winner: Oxlint (for speed), ESLint (for plugin ecosystem)

Oxlint vs Biome

Wait, didn’t you write about Biome? Yes! But they’re different tools:

Aspect Biome Oxlint
Focus All-in-one (linter + formatter + bundler) Linter only (focused)
Speed Fast (Rust) Faster (more optimized)
ESLint Compatibility Partial High (aims for 100%)
Type-Aware No Yes!
Plugin System No Yes (coming soon)
Use Case Replace ESLint + Prettier Replace ESLint only

Winner: Biome for all-in-one, Oxlint for ESLint replacement

Oxlint vs TypeScript Compiler (tsc –noEmit)

Aspect tsc –noEmit Oxlint
Type Checking ✅ Full ✅ Type-aware rules
Linting ❌ No ✅ 700+ rules
Speed Slow (30-60s) Fast (0.1-3s)
Use Case Type checking Linting + type-aware rules

Winner: Use both! tsc for type checking, Oxlint for linting.


The Oxidation Compiler (Oxc) Ecosystem

Oxlint is just one tool from the Oxidation Compiler project. They’re building a full Rust-based JavaScript toolchain:

1. Oxc Parser (The Fastest JS Parser)

1
2
3
4
5
# Use it as a library
cargo add oxc_parser

# Or CLI
npx oxc-parser parse file.js # 50x faster than acorn

2. Oxc Transformer (Like Babel, but Fast)

1
2
# Transform JS/TS to older JS (like Babel)
npx oxc-transform file.ts --target es2015

3. Oxc Minifier (Like Terser, but Fast)

1
2
# Minify JS (like Terser)
npx oxc-minify file.js > file.min.js

4. Oxlint (The Linter)

1
2
# You know this one by now 😄
npx oxlint

5. Oxfmt (The Formatter, Coming Soon)

1
2
# Format code (like Prettier)
npx oxfmt file.js # Coming in 2026!

The goal? Replace the entire JavaScript toolchain with Rust:

1
2
Current:  Babel (slow) + ESLint (slow) + Prettier (slow) + Terser (slow)
Future: Oxc Transformer + Oxlint + Oxfmt + Oxc Minifier (all fast!)

Advanced: Using Oxlint with React + TypeScript

For a proper React + TypeScript setup, here’s the config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// oxlint.config.mjs
export default {
files: ['src/**/*.{ts,tsx}'],
ignores: ['node_modules', 'dist', 'build', '*.test.tsx'],

settings: {
react: {
version: 'detect', // Auto-detect React version
},
},

rules: {
// TypeScript rules
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unused-vars': ['error', { varsIgnorePattern: '^_' }],
'@typescript-eslint/explicit-function-return-type': 'off',

// React rules
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'react/no-unescaped-entities': 'warn',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',

// General rules
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-undef': 'error',
'no-unused-vars': 'error',
'prefer-const': 'error',
'no-var': ['error', 'always'],
},

// Enable type-aware linting
parserOptions: {
project: './tsconfig.json',
},
};

VS Code Settings (For Auto-Fix on Save)

1
2
3
4
5
6
7
8
// .vscode/settings.json
{
"oxc.enable": true,
"editor.codeActionsOnSave": {
"source.fixAll.oxc": true
},
"oxc.run": "onSave"
}

Now every time you save, Oxlint fixes lint errors instantly.


Performance Deep Dive: Why is Oxlint So Fast?

Let’s get technical for a second.

1. Rust + Parallelism

ESLint is single-threaded JavaScript. Oxlint is multi-threaded Rust:

1
2
ESLint: ████████████████░░░░░░ (1 thread, 12.3s)
Oxlint: ████░░░░░░░░░░░░░░ (16 threads, 0.12s)

2. Single-Pass AST Traversal

ESLint visits AST nodes once per rule:

1
2
3
4
5
6
7
// ESLint pseudo-code
for (const rule of rules) { // 300 iterations
ast.traverse(node => { // Visit all nodes
rule.check(node); // Check this node
});
}
// Total: 300 × (AST size) operations

Oxlint visits AST nodes once, running all rules:

1
2
3
4
5
6
7
// Oxlint (Rust) pseudo-code
ast.traverse(|node| { // Visit all nodes ONCE
for rule in rules { // Run all rules on this node
rule.check(node);
}
});
// Total: 1 × (AST size) operations

Result? 300x fewer AST traversals.

3. SIMD (Single Instruction, Multiple Data)

Oxlint uses SIMD instructions (if your CPU supports them) to process multiple characters at once:

1
2
3
4
5
6
7
8
9
10
11
12
// Instead of:
let mut i = 0;
while i < source.len() {
if source[i] == b'{' { ... } // Check one byte at a time
i += 1;
}

// Oxlint does:
let chunks = source.chunks_exact(16); // Process 16 bytes at once!
for chunk in chunks {
// SIMD magic 🧙
}

4. Zero-Copy String Handling

ESLint creates string copies everywhere. Oxlint uses zero-copy:

1
2
3
4
5
6
7
8
9
// ESLint (JavaScript)
const source = fs.readFileSync('file.js', 'utf8'); // Copy into memory
const ast = parse(source); // Another copy
// Total: 2-3x memory usage

// Oxlint (Rust)
let source = fs::read_to_string("file.js")?; // One allocation
let ast = parse(&source); // Borrow, no copy!
// Total: 1x memory usage

Real-World Case Studies

Case 1: Shopify (Production User)

Shopify migrated their entire codebase (100k+ files) to Oxlint:

  • Lint time: 8 minutes → 12 seconds
  • CI/CD time: 14 minutes → 4 minutes
  • Developer productivity: 📈📈📈
  • Money saved: ~$50,000/year (CI/CD costs)

Case 2: A Random Startup (Name Withheld)

A YC startup with a 80k LOC TypeScript monorepo:

  • ESLint time: 47 seconds
  • Oxlint time: 0.9 seconds
  • Migration time: 2 hours
  • ROI: Paid off in 1 day (from saved developer time)

Case 3: My Own Company

Our 50k LOC TypeScript monorepo:

  • ESLint: 12.3s
  • Oxlint: 0.12s
  • Pre-commit hook: 8.5s → 0.3s
  • Team happiness: Priceless

Advanced Configuration: Getting The Most Out Of Oxlint

1. Enable Caching (For CI/CD)

1
2
3
4
5
# Oxlint caches results by default
npx oxlint --cache

# Cache location: node_modules/.cache/oxlint/
# Second run? Instant!

2. Use Lint-Staged (For Pre-commit Hooks)

1
2
3
4
5
6
// package.json
{
"lint-staged": {
"*.{js,ts,tsx,jsx}": "oxlint --fix"
}
}

Now only staged files get linted. For a 10,000-file repo, this means 0.01 seconds per commit.

3. Enable All Rules (For New Projects)

1
2
3
4
5
6
7
8
9
10
# Run with all rules enabled (strict mode)
npx oxlint --rules all

# Or in config:
export default {
rules: {
// Enable all recommended rules
...builtinRules,
},
};

4. Custom Plugins (Advanced)

Oxlint is working on plugin support. For now, you can use ESLint plugins (many work out of the box):

1
2
3
4
5
6
7
// oxlint.config.mjs
export default {
plugins: {
// Some ESLint plugins work with Oxlint!
'eslint-plugin-react': require('eslint-plugin-react'),
},
};

Common Migration Issues (And How to Fix Them)

Issue 1: “Some ESLint Rules Are Missing”

Solution: Oxlint has 700+ rules, but not all ESLint rules are implemented yet.

1
2
3
4
5
6
7
# Check which rules are supported
npx oxlint --rules

# If a rule is missing, you can:
# 1. Wait for it to be implemented (they're adding rules fast!)
# 2. Use ESLint for that specific rule
# 3. Disable the rule temporarily

Issue 2: “Type-Aware Linting is Slow”

Solution: Make sure your tsconfig.json is correct:

1
2
3
4
5
6
7
8
9
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

Issue 3: “Oxlint Conflicts with ESLint”

Solution: Run both during migration:

1
2
3
4
5
6
7
8
// package.json
{
"scripts": {
"lint": "oxlint",
"lint:legacy": "eslint .", // Keep ESLint for transition period
"lint:all": "oxlint && eslint ." // Use both
}
}

Gradually migrate rules from ESLint to Oxlint.


The Downsides (Because Nothing is Perfect)

Let’s be honest — Oxlint isn’t perfect (yet).

1. Smaller Plugin Ecosystem

ESLint has 1000+ plugins. Oxlint has… fewer. But! It aims for ESLint compatibility, so many plugins work out of the box.

2. Newer = More Bugs

Oxlint is younger than ESLint. You might hit edge cases. But the Oxc team is incredibly responsive on GitHub — I once reported a bug and it was fixed in 24 hours.

3. Not a Drop-In Replacement (Yet)

ESLint has 10 years of ecosystem. Oxlint is catching up, but some plugins don’t work yet. Give it time.

4. Learning Curve (If You Love Configuring Things)

If you’re the kind of person who enjoys spending 3 hours configuring .eslintrc.json, you’ll be disappointed. Oxlint works out of the box.

(I consider this a feature, not a bug. 😄)


When Should You Use Oxlint?

✅ Use Oxlint If:

  1. You have a large codebase (10,000+ files) and ESLint is slow
  2. You want zero-config linting (install and go)
  3. You value your time (ESLint takes 30s, Oxlint takes 0.1s)
  4. You’re using TypeScript (type-aware linting is fast!)
  5. You want faster CI/CD (linting is often a bottleneck)

❌ Don’t Use Oxlint If:

  1. You rely on obscure ESLint plugins that haven’t been ported yet
  2. You’re on a legacy project with custom ESLint rules (migrate gradually)
  3. You enjoy waiting for linting to finish (weird flex, but ok)

Getting Started (3 Ways)

1
2
3
4
5
6
7
8
9
10
11
# Go to your project
cd my-awesome-project

# Install Oxlint
npm install -D oxlint

# Run it (zero config!)
npx oxlint

# If you like it, add to package.json:
# "lint": "oxlint"

Method 2: Use with lint-staged (For Pre-commit Hooks)

1
2
3
4
5
6
7
8
9
10
11
# Install dependencies
npm install -D husky lint-staged

# Add to package.json
{
"lint-staged": {
"*.{js,ts,tsx,jsx}": "oxlint --fix"
}
}

# Now linting runs on every commit (only staged files, super fast!)

Method 3: VS Code Extension (For Real-Time Linting)

1
2
3
4
1. Open VS Code
2. Search: "Oxc"
3. Install
4. Linting happens automatically!

The Future of Oxlint (2026 and Beyond)

The Oxc team has an ambitious roadmap:

2026 Q2-Q3 (Current)

  • ✅ Oxlint 1.0 (released, stable)
  • ✅ 700+ rules
  • 🔲 Full ESLint plugin compatibility

2026 Q4

  • 🔲 Oxfmt (Rust-based formatter, like Prettier)
  • 🔲 Better Vue/Svelte support
  • 🔲 Plugin system v1

2027

  • 🔲 Oxlint 2.0 (next major)
  • 🔲 AI-assisted linting (seriously, they’re discussing this)
  • 🔲 Full Oxidation Compiler toolchain (parser + transformer + linter + minifier + formatter)

FAQ (Because You Probably Have Questions)

“Is Oxlint production-ready?”

Yes. Oxlint 1.0 was released in March 2026. Shopify and other enterprises are using it in production.

“Do I need to rewrite my ESLint config?”

No. Oxlint reads .eslintrc.json automatically. Or you can start with zero config.

“Is Oxlint only for JavaScript?”

No. It supports TypeScript, React, Vue, Svelte, and plain JavaScript.

“What about Prettier? Should I use Oxlint instead?”

No. Oxlint is a linter (catches bugs). Prettier is a formatter (formats code). Use both! (Or wait for Oxfmt in 2026 Q4.)

“Is Oxlint free?”

Yes. MIT license. No catch. No paid tier.

“How is Oxlint different from Biome?”

Biome is all-in-one (linter + formatter + bundler). Oxlint is linter-focused and aims for 100% ESLint compatibility.


Final Verdict: Should You Switch?

If you’re using ESLint in 2026 and not using Oxlint, you’re sacrificing 100x speed for… what exactly?

Let me break it down:

You Should Use Oxlint If… You Should Stay With ESLint If…
Lint takes >5s You enjoy waiting
CI/CD is slow You have unlimited CI minutes
Team complains about lint speed You hate productivity
You value your time You have infinite time

Look, I’m not saying ESLint is bad. I’m saying it was good for 2015. In 2026, we have better tools.

Oxlint is that better tool.


Resources


Conclusion: The Speed You Deserve

Oxc Logo

I’ll keep this simple:

ESLint made linting accessible. Oxlint makes it fast.

If you’re still waiting 30 seconds for your linter to finish in 2026, you’re doing it wrong. Your time is worth more than that. Your team’s time is worth more than that.

Give Oxlint a shot. Run it on your project. Watch it lint 10,000 files in 0.12 seconds.

Then come back and thank me. Or buy me a beer. I like beer.

Happy linting! ⚡


P.S. — If you’re from the ESLint team and you’re reading this… I’m sorry. Actually, no, I’m not. Rewrite ESLint in Rust and maybe I’ll come back. Until then, I’m team Oxlint. 🤷

P.P.S. — This article was written while waiting 0 seconds for Oxlint to finish linting. It’s nice.