This document describes the migration of linting rules from ESLint plugins to oxlint for improved performance.
Oxlint is a high-performance linter built in Rust that can replace many ESLint rules and plugins. This migration moves most linting rules to oxlint while keeping ESLint for rules that oxlint doesn't yet support.
The following ESLint plugins have been fully migrated to oxlint:
-
eslint-plugin-jsx-a11y →
jsx-a11y-plugin- All accessibility rules for JSX are now handled by oxlint
- Package removed from dependencies
-
@next/eslint-plugin-next (partial) →
nextjs-plugin- Most Next.js specific rules are handled by oxlint
- ESLint still validates some Next.js conventions that oxlint doesn't cover
-
Basic ESLint Rules → Built-in oxlint categories
correctness: Code that is outright wrong or uselesssuspicious: Code that is most likely wrong or useless
The following remain in ESLint because oxlint doesn't fully support them:
-
eslint-plugin-react-refresh
- Validates Next.js metadata exports
- Custom configuration for
allowExportNames
-
eslint-plugin-import-x
- Import ordering rules
- Oxlint's import plugin is still experimental
-
@next/eslint-plugin-next (partial)
- Some Next.js core web vitals checks
- TypeScript-specific Next.js rules
The new oxlint configuration file enables:
- Plugins:
import,jsx-a11y,react-perf,nextjs - Categories:
correctnessandsuspiciousset to warn - Rules: Comprehensive jsx-a11y and Next.js rules
- Environment: Browser, Node.js, ES2024
Updated to:
- Remove
eslint-plugin-jsx-a11y(migrated to oxlint) - Add comments explaining what ESLint still handles
- Use
oxlint.configs['flat/recommended']to disable rules that oxlint handles
Updated pre-commit hooks:
- oxlint now uses
--config .oxlintrc.jsonflag - oxlint runs before ESLint for faster feedback
Updated scripts:
lint: Uses oxlint with config filelint:fix: Uses oxlint with config file and fix flag
Oxlint is significantly faster than ESLint:
- Written in Rust (vs JavaScript)
- Parallel processing by default
- Simpler architecture without plugin overhead
Example timing on this project:
- Oxlint: ~39ms on 1 file with 121 rules using 14 threads
- ESLint: ~2-3 seconds on the same file
Replaces eslint-plugin-jsx-a11y with all recommended accessibility rules:
alt-text,anchor-has-content,aria-props, etc.- Auto-fixable where possible
Handles Next.js specific rules:
no-img-element(use next/image)no-html-link-for-pages(use next/link)no-head-element(use next/head)- And many more Next.js best practices
Experimental plugin for import validation:
no-cycle: Prevent circular dependenciesno-duplicates: Prevent duplicate importsno-self-import: Prevent importing from same file
Performance-focused React rules:
- Currently disabled (
jsx-no-new-function-as-prop, etc.) - Can be enabled for stricter performance checks
| ESLint Plugin | ESLint Rule | Oxlint Plugin | Oxlint Rule | Status |
|---|---|---|---|---|
| jsx-a11y | alt-text | jsx-a11y | alt-text | ✅ Migrated |
| jsx-a11y | anchor-is-valid | jsx-a11y | anchor-is-valid | ✅ Migrated |
| jsx-a11y | aria-props | jsx-a11y | aria-props | ✅ Migrated |
| @next | no-img-element | nextjs | no-img-element | ✅ Migrated |
| @next | no-html-link-for-pages | nextjs | no-html-link-for-pages | ✅ Migrated |
| import-x | order | import-x | - | |
| react-refresh | only-export-components | react-refresh | - |
# Run both oxlint and ESLint
pnpm run lint
# Auto-fix with both linters
pnpm run lint:fix
# Run only oxlint
pnpm exec oxlint --config .oxlintrc.json
# Run only ESLint
pnpm exec eslint .Lefthook automatically runs both linters on staged files:
# Manual pre-commit check
lefthook run pre-commit
# Check all files
lefthook run pre-commit --all-filesThis is expected! Oxlint may:
- Be more strict in some areas
- Be less strict in others
- Have different fix suggestions
Both linters run in sequence, so you'll see errors from both.
The oxlint import plugin is experimental. If you encounter issues:
- Check that
--tsconfigis not needed in your case - Verify import paths are correct
- Fall back to ESLint's import-x plugin
If oxlint doesn't resolve TypeScript path aliases:
oxlint --config .oxlintrc.json --tsconfig ./tsconfig.jsonAs oxlint continues to evolve:
- Import Ordering: Migrate when oxlint's import plugin stabilizes
- React Refresh: Migrate when oxlint supports Next.js metadata exports
- Custom Rules: Remove ESLint entirely once all rules are supported
This migration achieves:
- ✅ 3-10x faster linting performance
- ✅ Comprehensive accessibility checking (jsx-a11y)
- ✅ Next.js best practices enforcement
- ✅ Maintains ESLint for unsupported rules
- ✅ Seamless pre-commit hook integration