# Linter

> Bun's fast, built-in linter for JavaScript, TypeScript, and JSX

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 `typescript` package
- Auto-fix with `--fix`
- Works with your existing ESLint or oxlint config

## Run the linter

```bash terminal icon="terminal"
bun lint
```

```txt
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`.

To lint specific files, pass paths or globs.

```bash terminal icon="terminal"
bun lint src "test/**/*.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.

```bash terminal icon="terminal"
bun lint --fix
```

## 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`, and `jsx-key`, if `react` is in your `package.json`
- **Tests**: leftover `test.only`, `expect()` without a matcher, un-awaited `.resolves`, and a few more, in files that import from `bun: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 runs `import` and `require()` in the same file.
- A name that starts with `_` may be unused.
- `done && done();` and `ok ? 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 a `case`, and `// fall-through` or `// no break` marks 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 React` counts as used in a file with JSX.

Each rule's page says what differs and how to change it.

- In `.d.ts` files only the errors run.
- An `eslint-disable` comment for a rule that is off is left alone.

## Configure rules

Rules live in `bunfig.toml`. Every built-in rule works the same way. There are no plugins to install.

```toml bunfig.toml icon="settings"
[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:

```txt
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](/lint/rules), or look one up from the terminal. In most terminals you can also click the rule name in a report.

```bash terminal icon="terminal"
bun lint --rules                 # list every rule
bun lint --explain prefer-const  # what it does, examples, options
```

### Turn on a group of rules

Categories switch on many rules at once: `correctness`, `suspicious`, `pedantic`, `perf`, `style`, `restriction`, `nursery`.

```toml bunfig.toml icon="settings"
[lint.categories]
suspicious = "warn"
perf = "warn"
```

## Ignore files

```toml bunfig.toml icon="settings"
[lint]
ignorePatterns = ["vendor/", "**/*.gen.ts"]
```

## Disable a rule in code

`bun lint` uses ESLint's comments, so existing ones keep working.

```ts
// 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.

```bash terminal icon="terminal"
bun lint --type-aware
```

```txt
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`](/runtime/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:

```toml bunfig.toml icon="settings"
[lint]
typeAware = true
```

Only want one of them? Turn it on like any other rule. You don't need `typeAware`.

```toml bunfig.toml icon="settings"
[lint.rules]
"@typescript-eslint/no-floating-promises" = "error"
```

To report type errors too, like `bun check` does, set `typeCheck = true` or pass `--type-check`.

## Git hooks

`--staged` lints only the files you're about to commit, so you don't need `lint-staged`.

```sh .git/hooks/pre-commit icon="terminal"
#!/bin/sh
bun lint --staged --fix
```

`--changed` lints the files that differ from your default branch. Pass a ref to compare with something else.

```bash terminal icon="terminal"
bun lint --changed
bun lint --changed=origin/dev
```

## CI

In GitHub Actions, `bun lint` annotates the pull request diff automatically.

```yaml .github/workflows/lint.yml icon="file-code"
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.

```json package.json icon="file-json"
{
  "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.

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:

```bash terminal icon="terminal"
bun lint --doctor
```

See the guides: [Migrate from ESLint](/guides/lint/migrate-from-eslint) and [Migrate from oxlint](/guides/lint/migrate-from-oxlint). For custom rules, see [ESLint plugins](/lint/plugins).

# CLI Usage

```bash
bun lint [flags] [files, directories, or globs]
```

### Rules

<ParamField path="--rule" type="string">
  Set a rule for this run: <code>--rule 'eqeqeq: [error, smart]'</code>
</ParamField>

<ParamField path="--type-aware" type="boolean">
  Also run the rules that need type information
</ParamField>

<ParamField path="--rules" type="boolean">
  List every built-in rule. Add <code>-f json</code> for machine-readable output
</ParamField>

<ParamField path="--explain" type="string">
  Print the documentation for a rule
</ParamField>

<ParamField path="--init" type="boolean">
  Add a <code>[lint]</code> section to <code>bunfig.toml</code>
</ParamField>

### Fixing

<ParamField path="--fix" type="boolean">
  Apply fixes and write the files
</ParamField>

<ParamField path="--fix-suggestions" type="boolean">
  Also apply suggestions, which may change what the code does
</ParamField>

<ParamField path="--fix-dry-run" type="boolean">
  Compute fixes without writing them. The <code>json</code> format includes the fixed code
</ParamField>

### Files

<ParamField path="--staged" type="boolean">
  Lint only the files staged in Git
</ParamField>

<ParamField path="--changed" type="string">
  Lint only the files that differ from a Git ref. Defaults to the default branch
</ParamField>

<ParamField path="--ignore-pattern" type="string">
  Skip files that match this glob. Can be repeated
</ParamField>

<ParamField path="--no-ignore" type="boolean">
  Lint ignored files too
</ParamField>

### Output

<ParamField path="-f, --format" type="string" default="pretty">
  <code>pretty</code>, <code>stylish</code>, <code>json</code>, <code>unix</code>, <code>github</code>,{" "}
  <code>junit</code>, <code>checkstyle</code>, <code>gitlab</code>, <code>sarif</code>, or <code>agent</code>
</ParamField>

<ParamField path="-o, --output-file" type="string">
  Write the report to a file
</ParamField>

<ParamField path="--quiet" type="boolean">
  Report errors only
</ParamField>

<ParamField path="--max-warnings" type="number">
  Exit with code 1 if there are more warnings than this
</ParamField>

<ParamField path="--all" type="boolean">
  Show every problem. By default, more than 50 identical problems are grouped
</ParamField>

### Tools

<ParamField path="--doctor" type="boolean">
  Show which rules of your ESLint or oxlint config run natively, and which packages you can remove
</ParamField>

<ParamField path="--print-config" type="string">
  Print the resolved config for a file
</ParamField>

`bun lint` also accepts the flags of ESLint and oxlint. Run `bun lint --help --all` to see them.
