Skip to content

Fix: Oxlint Not Working — .oxlintrc.json Config, Rule Mapping, TypeScript, and ESLint Coexistence

FixDevs · (Updated: )

Part of:  JavaScript & TypeScript Errors

Quick Answer

How to fix Oxlint errors — .oxlintrc.json not loaded, rules not matching ESLint output, TypeScript files not linted, plugin-react/typescript wiring, IDE extension setup, and running alongside ESLint.

The Error

You install Oxlint and the config file is silently ignored:

$ oxlint
# Uses defaults, ignores your .oxlintrc.json with custom rules.

Or rules you turned off keep firing:

// .oxlintrc.json
{
  "rules": {
    "no-unused-vars": "off"
  }
}
$ oxlint
src/util.ts:5:7
 no-unused-vars: 'x' is declared but never used

Or TypeScript-specific files give wrong results:

$ oxlint src/
# Only lints .js files, skips .ts entirely.

Or you can’t tell what rules differ between Oxlint and ESLint:

ESLint passes. Oxlint fails on the same file.

Why This Happens

Oxlint is a Rust-based linter from the Oxc project. It’s positioned as a fast, drop-in subset of ESLint — it implements the most popular ESLint rules natively in Rust, but with these caveats:

  • Not every ESLint rule exists. Oxlint has hundreds of rules but not all of ESLint’s 300+ plugins. Missing rules don’t error — they just don’t run.
  • Config syntax is its own. .oxlintrc.json is similar to .eslintrc.json but not identical. ESLint flat config (eslint.config.js) isn’t directly compatible.
  • Plugin namespacing differs. Oxlint groups rules by plugin (typescript, react, jest, etc.) but uses its own internal names. @typescript-eslint/no-unused-vars becomes typescript/no-unused-vars.
  • Designed to run alongside ESLint, not replace it. The recommended workflow is Oxlint as a fast first pass + ESLint for rules Oxlint doesn’t support (yet).

The deeper reason rule names diverge is architectural. ESLint’s rules live in user-installable npm packages that each contribute their own namespace; Oxlint’s rules are compiled into the binary and grouped by the original ESLint plugin they emulate. Oxlint had to pick a canonical name per rule, and it dropped the @typescript-eslint/ and eslint-plugin- prefixes for ergonomics. That choice keeps the config file shorter but breaks copy-paste from .eslintrc files. The same rule names also appear in editor diagnostics, so a search for “how do I disable this Oxlint error” frequently lands on ESLint documentation that no longer applies.

A second source of confusion is the speed of Oxlint’s iteration. Through 2024 and 2025, Oxlint shipped new plugin support, type-aware rules, and config format changes almost monthly. A .oxlintrc.json written for 0.4 may emit warnings on 0.10 about deprecated fields; a snippet from a blog post written six months ago may reference a rule that has since been renamed. Pinning the version in package.json and running oxlint --print-config are the two habits that prevent “it worked yesterday” debugging sessions.

Finally, Oxlint’s silent skipping is intentional. ESLint errors loudly on unknown rules, which made adopting it across a monorepo painful — every team had to agree on the plugin set or builds broke. Oxlint chose the opposite default: unknown rules are no-ops. That’s friendly for adoption but lethal for confidence. The mitigation is to enable --deny-warnings in CI and to use --print-config in a pre-commit hook so the team knows exactly what is and isn’t being checked.

Fix 1: Place .oxlintrc.json in the Right Location

Oxlint looks for .oxlintrc.json (or .oxlintrc) in the directory you run from and walks up:

// .oxlintrc.json — at project root
{
  "$schema": "./node_modules/oxlint/configuration_schema.json",
  "rules": {
    "no-unused-vars": "off",
    "no-console": "warn",
    "typescript/no-explicit-any": "error"
  },
  "ignorePatterns": [
    "dist/**",
    "node_modules/**"
  ],
  "env": {
    "browser": true,
    "node": true,
    "es2024": true
  }
}

Verify Oxlint picks up the config:

oxlint --print-config

This prints the merged config. If your custom rules don’t appear, the file isn’t being loaded — check the filename (must be .oxlintrc.json, not oxlintrc.json) and that you’re running from a directory under it.

Pro Tip: Pin the schema reference via $schema for editor autocomplete. The schema lives in node_modules/oxlint/configuration_schema.json after install.

Fix 2: Use Oxlint’s Plugin-Prefixed Rule Names

Oxlint groups rules by plugin. To target plugin rules:

{
  "plugins": ["typescript", "react", "jest", "unicorn"],
  "rules": {
    "typescript/no-explicit-any": "error",
    "typescript/no-unused-vars": "off",
    "react/jsx-key": "error",
    "react/no-array-index-key": "warn",
    "jest/no-disabled-tests": "warn",
    "unicorn/prefer-set-has": "error"
  }
}

Without "plugins" listing, plugin rules don’t run — even if you reference them in rules. The plugins enable the rule set; rules overrides severity.

For ESLint users migrating, the mapping is mostly:

ESLint ruleOxlint rule
@typescript-eslint/no-explicit-anytypescript/no-explicit-any
react-hooks/rules-of-hooksreact/rules-of-hooks
import/no-cycleimport/no-cycle
jest/no-disabled-testsjest/no-disabled-tests

The prefix follows the plugin’s “short name.” Run oxlint --help to see the available flags for listing rules in your installed version — recent releases support a flag to print the full rules table.

Common Mistake: Copying ESLint config verbatim. @typescript-eslint/* doesn’t work — drop the @typescript-eslint/ prefix and use typescript/.

Fix 3: Lint TypeScript Explicitly

Oxlint auto-detects .ts, .tsx, .cts, .mts if you pass a directory:

oxlint src/      # Lints all .js, .ts, .jsx, .tsx files

If you pass --ext flags:

oxlint --ext .ts,.tsx src/

Without the right extension list, Oxlint silently skips files.

For TS-specific rules (the typescript/* namespace), Oxlint doesn’t need type information for most rules — it works on the AST alone. A handful of rules that do need types (e.g. type-aware unused checks) are explicitly marked in the docs.

{
  "plugins": ["typescript"],
  "rules": {
    "typescript/no-explicit-any": "error",
    "typescript/consistent-type-imports": "warn",
    "typescript/no-non-null-assertion": "warn"
  }
}

Fix 4: Categories Pre-Configured Sets

Oxlint exposes rule categories you can opt into wholesale:

{
  "categories": {
    "correctness": "error",
    "suspicious": "warn",
    "perf": "warn",
    "pedantic": "off",
    "style": "off",
    "restriction": "off"
  }
}

Or via CLI:

oxlint -W perf -W suspicious src/

correctness is on by default. The other categories opt-in based on how strict you want to be:

  • correctness — likely bugs (unused vars, unreachable code, no-debugger).
  • suspicious — code that’s probably wrong but not certainly.
  • perf — performance smells (for-each on large arrays, etc.).
  • pedantic — stricter style/safety guidance.
  • style — pure formatting/style.
  • restriction — bans on specific patterns (no-console, no-debugger).

For a balanced default, enable correctness + suspicious + perf. Add pedantic once the easier ones are clean.

Fix 5: Run Alongside ESLint, Not Instead

The most pragmatic adoption pattern: Oxlint runs first (catches the common issues fast), then ESLint for plugin rules Oxlint hasn’t ported:

{
  "scripts": {
    "lint": "oxlint && eslint .",
    "lint:fast": "oxlint",
    "lint:full": "eslint ."
  }
}

In eslint.config.js, exclude rules that Oxlint already covers to avoid double-reporting:

import oxlint from "eslint-plugin-oxlint";

export default [
  // ... your other configs
  // This must be the last config in the chain.
  ...oxlint.configs["flat/recommended"],
];

eslint-plugin-oxlint disables ESLint rules that Oxlint already implements — your ESLint pass becomes the “rules Oxlint doesn’t support yet” pass.

Pro Tip: Run Oxlint in pre-commit hooks and CI’s first job; run ESLint in a separate (slower) CI job. Oxlint catches 90% of issues in milliseconds.

Fix 6: IDE Integration

For VS Code:

# Install the Oxc extension from the marketplace:
# "Oxc" by oxc.rs

The extension uses Oxlint’s LSP for in-editor lints. Configure in .vscode/settings.json:

{
  "oxc.enable": true,
  "oxc.lint.run": "onType",  // or "onSave"
  "oxc.path": "./node_modules/.bin/oxlint"
}

For JetBrains IDEs: there’s an Oxc plugin under development; until then, run Oxlint via a file watcher.

For Neovim: use nvim-lspconfig with the Oxc LSP:

require("lspconfig").oxc.setup({})

Common Mistake: Running both ESLint and Oxlint extensions in the IDE at full strength. You’ll see duplicate squiggles. Disable rules Oxlint covers in your ESLint config (see Fix 5).

Fix 7: Ignore Files

Oxlint supports ignorePatterns in .oxlintrc.json and a separate .oxlintignore:

{
  "ignorePatterns": [
    "dist/**",
    "build/**",
    "**/*.generated.ts",
    "vendor/**"
  ]
}

Patterns use gitignore-style globs. For more complex ignore logic:

# .oxlintignore
dist/
build/
coverage/
**/*.min.js
**/*.generated.*

Oxlint also respects .gitignore by default (don’t lint what git ignores). If you need to lint something .gitignored, override via the CLI:

oxlint --no-ignore <file>

Fix 8: Performance Tuning

Oxlint is fast by default. For monorepos with hundreds of thousands of files:

oxlint --threads 8 src/

--threads defaults to the CPU count. Manually capping it helps when CI machines have ulimit issues.

For caching across CI runs (Oxlint doesn’t natively cache yet — but you can scope):

# Only lint files changed since main:
oxlint $(git diff --name-only origin/main...HEAD | grep -E '\.(ts|tsx|js|jsx)$')

Pro Tip: Oxlint typically runs 50-100x faster than ESLint on the same files. If your Oxlint run still feels slow, you’re probably linting too many files — check ignorePatterns.

Version History and Tooling Context

Oxlint moves fast — the table below covers the milestones that matter when you’re reading docs, copying configs, or pinning versions:

  • Oxlint 0.1 (October 2023) shipped the first public release: roughly 100 ported ESLint rules, no plugin namespacing, JSON-only config. Configs from this era look surprisingly different from what’s current.
  • Oxlint 0.2 added the type-aware preview. A subset of typescript/* rules began using TypeScript-style type information, though the API for enabling them was experimental.
  • Oxlint 0.4 (July 2024) introduced the plugin model and the plugins field in .oxlintrc.json. This is when typescript/no-explicit-any and react/jsx-key became the canonical naming. Almost all current tutorials assume 0.4 or later.
  • Oxlint 0.6–0.9 added React, Jest, Unicorn, JSDoc, and N (node) plugin families and stabilized the categories system (correctness, suspicious, perf, pedantic, style, restriction). The --threads flag landed here as well.
  • Oxlint 0.10+ improved ESLint compatibility: more // eslint-disable-next-line directives are read, more eslint-plugin-* rule mappings are recognized, and the LSP for editor integration matured. The eslint-plugin-oxlint package became stable around this point as the canonical way to disable doubled-up ESLint rules.
  • Oxlint 0.13+ introduced richer JSONC support in config files and tightened the schema (extra fields now warn). If you upgrade and suddenly see warnings about unknown config keys, this is why.

Compared to alternatives: Biome (formerly Rome) is also a Rust-based linter and formatter, but its rule set was reimagined from scratch rather than ported from ESLint, so it’s less drop-in but more cohesive. ESLint 9 with flat config is still the most flexible option — every plugin ever written for it works — but it’s an order of magnitude slower than Oxlint. Quick-Lint-JS focuses on real-time editor integration but doesn’t aim for the breadth of either tool. The practical 2026 pattern is: Oxlint as the fast gate in pre-commit and CI, ESLint or Biome for rules Oxlint hasn’t ported, and eslint-plugin-oxlint keeping the two in sync so nobody flags the same issue twice.

Still Not Working?

A few less-obvious failures:

  • Rule severity says "warn" but CI fails. Some tools (oxlint --deny-warnings or --max-warnings 0) escalate warnings to failures. Check your CI command.
  • .oxlintrc.json has comments and fails to parse. Standard JSON doesn’t allow comments. Use .oxlintrc.json with no comments, or .oxlintrc.jsonc if your version supports JSONC.
  • Auto-fix not working for some rules. Only a subset of rules are auto-fixable. Use oxlint --fix to apply the fixable ones; the unfixable ones still need manual edits.
  • Disabling a rule per-line with // eslint-disable-line doesn’t work. Oxlint uses its own directive: // oxlint-disable-next-line rule-name. Or use ESLint-compatible directives (Oxlint reads // eslint-disable-next-line too as of recent versions).
  • Plugin not recognized. Check Oxlint’s release notes — plugin support is being added incrementally. A rule from eslint-plugin-import may or may not be in your Oxlint version.
  • Different output between local and CI. Different Oxlint versions. Pin in package.json: "oxlint": "0.10.0" (exact), not ^0.10.0.
  • Lint fails on JSX without React import. Oxlint’s react/react-in-jsx-scope defaults assume classic JSX runtime. Disable it for projects on the automatic runtime: "react/react-in-jsx-scope": "off".
  • Globals not recognized. globals in config or /* global Foo */ directives. Add browser/node globals via env:
{
  "env": {
    "browser": true,
    "node": true
  },
  "globals": {
    "MY_CUSTOM_GLOBAL": "readonly"
  }
}
  • oxlint exits 0 but Biome flags the same file. The two tools share rule names but apply different defaults. Set a category ("correctness": "error") to force the rule on rather than relying on Biome-style implicit defaults.
  • Editor shows different errors than CLI. The Oxc LSP and the oxlint CLI sometimes resolve different .oxlintrc.json files when you have nested configs. Run oxlint --print-config <file> from the project root to see which config the CLI uses, then point the editor at the same one via oxc.path.
  • oxlint --fix rewrites code your formatter then changes back. Oxlint’s fixer and Prettier disagree on whitespace in a handful of cases (trailing commas, JSX whitespace). Run Prettier after oxlint --fix in your package.json script, and add lint:fix && format as a single command so neither tool is the last writer alone.
  • Rule disabled in config still fires in CI. Some monorepo configurations have multiple .oxlintrc.json files; the one nearest the file being linted wins. Move overrides to the root or use overrides arrays to scope them correctly.

For related linting, formatting, and bundler tooling issues, see Biome not working, ESLint config not working, ESLint parsing error unexpected token, and ESLint no-unused-vars false positive.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles