Bun Linter
Bun 内置的快速 JavaScript、TypeScript 与 JSX 代码检查器
当前显示英文原文。内容会随官方文档同步更新。
阅读英文原文bun lint 是 Bun 内置的快速代码检查器,可以直接读取 ESLint flat config,并在大多数项目中替代 ESLint。
Bun ships with a fast, built-in linter. There's nothing to install and nothing to configure.
- 1,000+ rules from ESLint, typescript-eslint, React, import, unicorn, jsx-a11y, Jest, Vitest, and more
- Type-aware rules, without the
typescriptpackage - Auto-fix with
--fix - Works with your existing ESLint or oxlint config
Run the linter
bun lint
1 | export function total(prices: number[]) {
2 | let sum = 0;
3 | for (let i = 0; i < prices.length; i--) {
^
error: The update clause in this loop moves the variable in the wrong direction. for-direction
at src/cart.ts:3:3
5 | }
6 |
7 | let tax = 0.2;
^
warn: 'tax' is never reassigned. Use 'const' instead. prefer-const
at src/cart.ts:7:7
2 problems (1 error, 1 warning)
1 can be fixed with --fix
Linted 1 file [5.17ms]
bun lint checks every .js, .jsx, .ts, and .tsx file in the current directory (plus the .mjs, .cjs, .mts, .cts variants). It skips node_modules and anything in your .gitignore or .git/info/exclude.
To lint specific files, pass paths or globs.
bun lint src "test/**/*.test.ts"
An argument that starts with ! leaves files out of what the other arguments select, as it does for bun fmt. This holds with an ESLint or oxlint config too.
bun lint src "!src/generated" "!**/*.test.ts"
The exit code is 1 if there are errors and 0 if there are only warnings.
Fix problems
Many rules can fix what they report. --fix applies those fixes and writes the files.
bun lint --fix
--fix is for changes that keep what your program does and keep your comments. Where a rule's fix is known to alter behavior or drop a comment, the problem is still reported, but only --fix-suggestions or --fix-dangerously applies the fix, even if ESLint or oxlint apply it with --fix. Each rule's page says which flag it needs.
Default rules
With no config, bun lint turns on the rules that catch real bugs:
- Every file: ESLint's recommended rules
- TypeScript: typescript-eslint's recommended rules
- React:
rules-of-hooks,exhaustive-deps, andjsx-key, ifreactis in yourpackage.json - Tests: leftover
test.only,expect()without a matcher, un-awaited.resolves, and a few more, in files that import frombun:test
Likely bugs are errors. Unused code, style suggestions, and code that people often write on purpose, like while (match = re.exec(text)), are warnings. A warning doesn't fail the run.
A few defaults differ from ESLint's, so that ordinary code isn't reported:
require()is allowed in TypeScript files. Bun runsimportandrequire()in the same file.- A name that starts with
_may be unused. done && done();andok ? resolve() : reject();are fine as statements.- A no-break space or a full-width space is only reported in code, not in text, comments or JSX.
process.exit()ends acase, and// fall-throughor// no breakmarks one that goes on.{false && <Debug />}is a fine way to switch something off for a while.- An array of JSX elements needs keys only where React renders it as a list.
import Reactcounts as used in a file with JSX.
Each rule's page says what differs and how to change it.
- In
.d.tsfiles only the errors run. - An
eslint-disablecomment for a rule that is off is left alone.
Configure rules
Rules live in bunfig.toml. Every built-in rule works the same way, with nothing to install. The exceptions are the rules for JSON and Markdown, which need an ESLint config.
[lint.rules]
"no-console" = "warn"
"prefer-const" = "off"
"eqeqeq" = ["error", "smart"] # with options
"unicorn/prefer-node-protocol" = "error"
"@typescript-eslint/no-explicit-any" = "off"
An option you don't set keeps its default.
To create the section, run bun lint --init.
A typo is an error, not a silent no-op:
2 | "no-consle" = "warn"
^
error: Unknown rule "no-consle"
Did you mean "no-console"?
at bunfig.toml:2:1
Find a rule
Browse all rules, or look one up from the terminal. In most terminals you can also click the rule name in a report.
bun lint --rules # list every rule
bun lint --explain prefer-const # what it does, examples, options
Add an ESLint plugin
Need a rule that isn't built in? Load any ESLint plugin, from npm or your own. The default rules stay on.
[lint]
plugins = ["eslint-plugin-perfectionist", "./lint/plugin.js"]
[lint.rules]
"perfectionist/sort-imports" = "error"
"local/no-todo" = "warn"
Turn on a group of rules
Categories switch on many rules at once: correctness, suspicious, pedantic, perf, style, restriction, nursery.
[lint.categories]
suspicious = "warn"
perf = "warn"
A category includes the React, Next.js, Jest and Vitest rules only if your package.json lists that package. See lint.categories.
Turn a plugin off
Use * as the rule name to turn off every rule of a plugin. A setting for a single rule overrides it.
[lint.rules]
"jsx-a11y/*" = "off"
"unicorn/*" = "off"
"unicorn/no-null" = "warn"
Ignore files
[lint]
ignorePatterns = ["vendor/", "**/*.gen.ts"]
The patterns use .gitignore syntax and are relative to bunfig.toml. With an eslint.config.* file they're ESLint ignores instead.
ES modules and CommonJS
bun lint works out whether a file is an ES module or CommonJS from the file itself, the way Node.js does:
.mjsand.mtsfiles are modules..cjsand.ctsfiles are CommonJS.- Any other file is a module if the nearest
package.jsonhas"type": "module". - Otherwise, a file with an
import, anexport,import.metaor a top-levelawaitis a module. A file with none of them is CommonJS.
A CommonJS file can return at the top level, and it's only in strict mode if it starts with "use strict".
To decide for every file yourself, set sourceType to "module", "commonjs" or "script":
[lint.parserOptions]
sourceType = "commonjs"
Next to an eslint.config.js, ESLint's defaults apply instead: .js and .mjs files are modules and .cjs files are CommonJS, unless languageOptions.sourceType says otherwise.
Disable a rule in code
bun lint uses ESLint's comments, so existing ones keep working. oxlint's oxlint-disable comments mean the same, except next to an ESLint config, where they are ordinary comments as in ESLint.
// eslint-disable-next-line no-console -- the CLI prints its version
console.log(version);
/* eslint-disable no-console */
console.log("off until the end of the file");
A comment that no longer disables anything gets a warning, and --fix removes it.
Type-aware rules
Some bugs only show up with types, like a promise nobody awaits. --type-aware turns on the recommended rules that use them.
bun lint --type-aware
5 | export function onClick() {
6 | save("hello");
^
error: Promises must be awaited, end with a call to .catch, ... @typescript-eslint/no-floating-promises
at src/save.ts:6:3
Types come from bun check, Bun's built-in type checker. It's slower than a plain run, because your code is type checked first. To make it the default:
[lint]
typeAware = true
Only want one of them? Turn it on like any other rule. You don't need typeAware.
[lint.rules]
"@typescript-eslint/no-floating-promises" = "error"
To report type errors too, like bun check does, set typeCheck = true or pass --type-check.
Choosing a tsconfig.json
Each file is type checked with the tsconfig.json your editor would use for it. To use one tsconfig.json for the whole run, pass --tsconfig.
bun lint --type-aware --tsconfig tsconfig.lint.json
A tsconfig.json without "include" covers every file below it. At the root of a monorepo, that can mean loading the whole repository to lint one package. Bun warns you when that happens.
warn: Loaded 10,114 files in 1.4s to lint vite.config.ts
../../tsconfig.json has no "include", so it covers every file under it.
To speed this up, add "include" to it or pass --tsconfig.
With an oxlint config, --tsconfig does what it does in oxlint. It sets the tsconfig.json that the import rules resolve imports with, for its paths. It doesn't change which tsconfig.json a file is type checked with, so the warning only suggests "include".
Git hooks
--staged lints only the files you're about to commit, so you don't need lint-staged.
#!/bin/sh
bun lint --staged --fix
If a file has both staged and unstaged changes, Bun lints the staged version, which is what the commit gets. --fix doesn't write such a file, because staging it again would commit the rest. If it has something to fix, Bun names the file and exits with code 2.
The same goes for the files that a staged file imports, which the type-aware rules and the import rules read. A file you staged and then deleted is still linted. Config files, such as bunfig.toml and eslint.config.js, are read from disk.
--changed lints the files that differ from your default branch. Pass a ref to compare with something else.
bun lint --changed
bun lint --changed=origin/dev
CI
In GitHub Actions, bun lint annotates the pull request diff automatically.
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun lint --max-warnings 0 # fail on warnings too
For other systems, pick a report format with --format: json, junit, checkstyle, gitlab, sarif, unix.
Migrate from ESLint or oxlint
Already have an eslint.config.js, .eslintrc, or .oxlintrc.json? bun lint reads it and reports what that tool reports. Change the script and you're done.
{
"scripts": {
"lint": "eslint ." // [!code --]
"lint": "bun lint" // [!code ++]
}
}
If package.json has a lint script, bun lint runs that script. Inside the script, bun lint is the linter. If package.json has "lint" in it but can't be parsed, as in the middle of a merge, bun lint can't tell whether that is a script: it lints nothing and exits with code 2.
Writing a tool that calls Bun in projects you don't control? Pass --no-script: bun lint --no-script is always the linter.
Rules from built-in plugins run natively. Any other ESLint plugin still runs, in JavaScript. To see which is which, and which packages you can uninstall:
bun lint --doctor
See the guides: Migrate from ESLint and Migrate from oxlint. For custom rules, see ESLint plugins.
CLI Usage
bun lint [flags] [files, directories, or globs]
Rules
--rulestringSet a rule for this run: --rule 'eqeqeq: [error, smart]'. Turn off a plugin:
--rule 'unicorn/*: off'
--type-awarebooleanAlso run the rules that need type information
--rulesbooleanList every built-in rule. Add -f json for machine-readable output
--explainstringPrint the documentation for a rule
--initbooleanAdd a [lint] section to bunfig.toml
Fixing
--fixbooleanApply fixes and write the files
--fix-suggestionsbooleanAlso apply suggestions, which may change what the code does
--fix-dry-runbooleanCompute fixes without writing them. The json format includes the fixed code
Files
--stagedbooleanLint only the files staged in Git
--changedstringLint only the files that differ from a Git ref. Defaults to the default branch
--ignore-patternstringSkip files that match this glob. Can be repeated
--no-ignorebooleanLint ignored files too
Output
-f, --formatstringdefault prettypretty, stylish, json, unix, github,
junit, checkstyle, gitlab, sarif, or agent
-o, --output-filestringWrite the report to a file
--quietbooleanReport errors only
--max-warningsnumberExit with code 1 if there are more warnings than this
--allbooleanShow every problem. By default, more than 50 identical problems are grouped
Tools
--doctorbooleanShow which rules of your ESLint or oxlint config run natively, and which packages you can remove
--print-configstringPrint the resolved config for a file
--no-scriptbooleanRun the linter even if the project has a lint script
bun lint also accepts the flags of ESLint and oxlint. Run bun lint --help --all to see them.