Migrate from oxlint to bun lint

bun lint reads your .oxlintrc.json and reports the same problems as oxlint 1.87. In most projects you only change the command.

package.json
{
  "scripts": {
    "lint": "oxlint --deny-warnings", 
    "lint": "bun lint --deny-warnings" 
  }
}

Flags and arguments stay the same: oxlint -D no-console src becomes bun lint -D no-console src. Change CI, lint-staged, and Git hooks too.

Edit the script first. If package.json has a lint script, bun lint runs that script, so you'd still get oxlint.


Run it. The problems, messages, help texts, and exit code are oxlint's.

terminal
bun run lint
$ bun lint --deny-warnings
1 | export function label(value: unknown) {
2 |   console.log(value);
      ^
warn: Unexpected console statement.  no-console
   at src/index.ts:2:3

note: Delete this console statement.

1 | export function label(value: unknown) {
2 |   console.log(value);
3 |   return typeof value === "strng" ? value : "none";
                              ^
error: Invalid `typeof` comparison value.  valid-typeof
    at src/index.ts:3:27

note: Did you mean `"string"`?

Linted 1 file [6.46ms]
error: script "lint" exited with code 1

Only the default layout is Bun's. Every other format, such as -f unix, -f json, or -f github, prints exactly what oxlint prints.


Run --doctor to see what Bun does with your config. It doesn't lint or write anything.

terminal
bun lint --doctor
Using .oxlintrc.json (oxlint config)

    1 file to lint

  116 rules run natively
    0 rules run in JavaScript
   25 rules do not run
       25 need types, use --type-aware: @typescript-eslint/await-thenable, @typescript-eslint/consistent-return, @typescript-eslint/no-array-delete, ..

You can remove: oxlint
Not checked:    other tools' configs, CI files, Git hooks

oxlint also skips type-aware rules unless you pass --type-aware, so you lose nothing here.


Uninstall oxlint.

terminal
bun remove oxlint oxlint-tsgolint

import { defineConfig } from "oxlint" in an oxlint.config.ts keeps working without the package.

No config file? Then Bun only uses oxlint's defaults while package.json depends on oxlint. To keep them, add an empty .oxlintrc.json before you uninstall. Without it you get Bun's defaults.

.oxlintrc.json
{}

Don't use oxlint --init for this. It sets the correctness category to "error", but oxlint's default is "warn", so warnings turn into errors and the exit code changes.


You can drop lint-staged. --staged lints only the staged files, and with --fix it stages the fixed files again.

.husky/pre-commit
npx lint-staged 
bun lint --staged --fix 

--type-aware and --type-check work without oxlint-tsgolint. The types come from Bun's built-in type checker (bun check).

terminal
oxlint --type-aware 
bun lint --type-aware 

jsPlugins work. Bun runs them in JavaScript. See ESLint plugins.

.oxlintrc.json
{
  "jsPlugins": ["./lint/plugin.js"],
  "rules": { "local/no-todo": "warn" }
}

If the project also has an ESLint config, Bun uses the oxlint config. Pick the other one with --config.

package.json
{
  "scripts": {
    "lint": "oxlint && eslint", 
    "lint": "bun lint && bun lint --config eslint.config.js" 
  }
}

Differences from oxlint#

If bun lint and oxlint 1.87 disagree about a rule, that's a bug. Open an issue. These differences are intentional:

  • The rules are oxlint 1.87's, whatever version you had installed.
  • No jsdoc/* or vue/* rules. If you turn one on by name, the run exits with code 2. If you only list the plugin, you get a note.
  • An unknown rule doesn't stop the run. oxlint rejects the config. Bun runs the other rules, then exits with code 2. --allow-unsupported turns that into a warning.
  • Output is sorted by file and line. oxlint prints files as its threads finish.
  • Syntax errors can be worded differently. oxlint also rejects a few programs that Bun lints, such as let a; let a;.
  • Patterns in rule options are JavaScript regular expressions. oxlint uses Rust's regex crate.
  • Control flow rules follow ESLint where oxlint differs: no-unreachable, no-fallthrough, getter-return, array-callback-return, constructor-super, no-this-before-super, no-useless-assignment.
  • --fix never writes a file that no longer parses. Bun leaves the file alone and warns.
  • --init adds [lint] to bunfig.toml, not an .oxlintrc.json. If you already have an oxlint config, it does nothing.
  • No language server. --lsp is an error. Keep oxlint if your editor's oxc extension uses it.

See also: