Skip to content

Linter

Biome’s linter statically analyzes your code to find and fix common errors and to help you write better, modern code. It supports multiple languages and provides a total of 311 rules.

You can quickly try the Biome linter via the CLI. The following command runs the linter on all files from the root of your project:

Terminal window
npx @biomejs/biome lint

Or you can specify one or multiple folders, for example ./src and ./public

Terminal window
npx @biomejs/biome lint ./src ./public

The command accepts a list of files and directories.

For more information about all the available options, check the CLI reference.

The linter is organized into rules. A rule is meant to enforce or deny a code style, the use of something that could lead to a bug, and more. Generally, a rule shouldn’t conflict with another rule, unless told otherwise. Biome rules have a naming convention: Rules that start with use* are meant to enforce/suggest something, while rules that start with no* are meant to deny something. When a rule encounters a violation of its concept, it emits a diagnostic.

For example, the noDebugger denies the use of debugger statements in JavaScript code, and it emits a diagnostic when it finds one.

Biome linter ships with a set of recommended rules that varies based on languages, which are enabled by default when you avail of the default Biome configuration (or no-configuration) when you run the lint or check command:

Terminal window
biome lint
biome check

Each lint rule ships with a default severity which you can lean more about by reading the documentation of the rule.

The rules are divided into groups. For example, the noDebugger rule is part of the suspicious group.

Biome supports language-agnostic rules. Those are rules that work across more than one language, such as noUselessEscapeInString, which can report useless escape sequences in both JavaScript and CSS.

Unlike other linters, Biome doesn’t provide any rules that check for code formatting; the Biome formatter is intended to handle all formatting decisions.

Many rules provide a code fix that can be automatically applied.

Biome makes a difference between safe fixes and unsafe fixes, which work slightly differently: The main difference is that safe fixes can be automatically applied when saving a file, while unsafe fixes can’t. Users can override which fixes are considered safe however.

Biome linter comes with a set of recommended rules that are automatically enabled, and vary based on the language.

Safe fixes are guaranteed to not change the semantic of your code. They can be applied without explicit review.

To apply safe fixes from the CLI, use --write:

Terminal window
npx @biomejs/biome lint --write ./src

From an LSP-compatible editor, you can apply safe fixes on save with the code action source.fixAll.biome. Refer to the documentation of your extension to learn how to apply it.

Unsafe fixes may change the semantic of your program. Therefore, it’s advised to manually review the changes.

To apply both safe fixes and unsafe fixes from the CLI, use --write --unsafe:

Terminal window
npx @biomejs/biome lint --write --unsafe ./src

From an LSP-compatible editor, it’s not possible to apply all unsafe fixes on save. It would be undesirable to change the semantics of your code on save. However, you can review the single code fix and choose to apply it.

In Biome, rules should be informative and explain to the user why a rule is triggered and tell them what they should to do fix the error. A rule should follow these pillars:

  1. Explain to the user the error. Generally, this is the message of the diagnostic.
  2. Explain to the user why the error is triggered. Generally, this is implemented with an additional node.
  3. Tell the user what they should do. Generally, this is implemented using a code action. If a code action is not applicable a note should tell the user what they should do to fix the error.

If you think a rule doesn’t follow these pillars, please open an issue.

In many cases, you want to change the linter based on your personal needs, or the needs or your organisation/project. Biome allows you to customise the linter, and in this section you will learn how to do it.

You can turn off a rule with off.

The following configuration disables the recommended rule noDebugger:

biome.json
{
"linter": {
"rules": {
"suspicious": {
"noDebugger": "off"
}
}
}
}

You can disable the recommended rules with a simple configuration. This may be useful in cases when you only want to enable a few rules.

{
"linter": {
"rules": {
"recommended": false
}
}
}

Biome lint rules are shipped with their own default severity. If you want to avail of rule default severity, you can use the "on" configuration.

For example the noShoutyConstants isn’t recommended by default, and when it’s triggered in emits a diagnostic with information severity.

If you’re happy with this default and you want to avail of it, the configuration will look like this:

biome.json
{
"linter": {
"rules": {
"style": {
"noShoutyConstants": "on"
}
}
}
}

If you aren’t happy with the default severity, Biome allows you to change it with "error", "warn" and "info"

Diagnostics with the "error" always cause the CLI to exit with an error code. This severity can be useful when you want to block the CI if there’s a violation that belongs to a certain rule.

Warnings are similar to errors, but they don’t cause the CLI to exit with an error code, unless the --error-on-warnings flag is used. A possible use for the warn severity is when you want to make the CI pass while there are still diagnostics for a given rule.

The info severity won’t affect the exit status code of the CLI, even when --error-on-warnings is passed.

Additionally, you can control the severity of lint rules at the group level. This way, it’s possible to control the diagnostic severity of all rules that belong to a group.

For example, a project doesn’t require the use of a11y rules because it’s code that runs at the backend, so accessibility isn’t a concern. The following example turns off all rules that belong to the a11y group:

{
"linter": {
"rules": {
"a11y": "off"
}
}
}

As explained above, rules might emit code fixes that are safe or unsafe. Biome allows configuring a safe fix to be treated as unsafe and vice-versa. You can also turn the code fix off entirely.

Code fixes can be configured using the fix option. It can have one of three values:

  • none: the rule won’t emit a code fix;
  • safe: the rule will emit a safe fix;
  • unsafe: the rule will emit an unsafe fix;
biome.jsonc
{
"linter": {
"rules": {
"correctness": {
"noUnusedVariables": {
"level": "error",
"fix": "none" // no code fix suggested for noUnusedVariables
}
},
"style": {
"useConst": {
"level": "warn",
"fix": "unsafe" // the code fix for `useConst` is now considered unsafe
},
"useTemplate": {
"level": "warn",
"fix": "safe" // the code fix for `useTemplate` is now considered safe
}
}
}
}
}

The command biome lint accepts an option --skip that allows disabling individual rules or groups of rules.

For example, the following command skips all the rules that belong to the style group and the suspicious/noExplicitAny rule:

Terminal window
biome lint --skip=style --skip=suspicious/noExplicitAny

The command biome lint accepts an option --only that allows running individual rules or groups of rules.

For example, the following command runs only the rule style/useNamingConvention, the rule style/noInferrableTypes and the rules that belong to a11y. If the rule is disabled in the configuration, then its severity level is set to error for a recommended rule or warn otherwise.

Terminal window
biome lint --only=style/useNamingConvention --only=style/noInferrableTypes --only=a11y

A few rules have options. You can set them by shaping the value of the rule differently.

  • level will indicate the severity of the diagnostic;
  • options will change based on the rule.
biome.json
{
"linter": {
"rules": {
"style": {
"useNamingConvention": {
"level": "error",
"options": {
"strictCase": false
}
}
}
}
}
}

Domains are a Biome feature that allow for grouping rules by technology, or well, domain. Examples of domains are "react", "solid", and "test".

A domain:

  • Has its own set of recommended rules.
  • Can be automatically enabled when Biome detects certain dependencies in your package.json file.
  • Can define additional global variables.

Biome’s linter will automatically enable the rules that belong to a domain when it detects certain dependencies in the nearest package.json. For example, if the mocha dependency is detected, Biome will enable the recommended rules of the test domain.

However, if there’s no package.json or the default configuration doesn’t apply, you can enable the domain via configuration:

biome.json
{
"linter": {
"domains": {
"test": "recommended"
}
}
}

Additionally, you can enable all rules that belong to a domain using the "all" value:

biome.json
{
"linter": {
"domains": {
"test": "all"
}
}
}

Like rules and groups, you can also turn the rules that belong to a domains with the "off" value:

biome.json
{
"linter": {
"domains": {
"test": "off"
}
}
}

To learn more about each domain, consult the appropriate page.

There are times when a developer wants to suppress a lint rule for a specific line of the code, more lines of code, or the entire file.

Biome provide different ways suppress lint rule using specific comments called suppression comments.

Suppression comments have the following format:

// biome-ignore lint: <explanation>
// biome-ignore lint/suspicious: <explanation>
// biome-ignore lint/suspicious/noDebugger: <explanation>
// biome-ignore lint/suspicious/noDebugger(foo): <explanation>
// biome-ignore-all lint: <explanation>
// biome-ignore-start lint: <explanation>
// biome-ignore-end lint: <explanation>

Let’s break it down:

  • biome-ignore, biome-ignore-all, biome-ignore-start and biome-ignore-end are the start of a suppression comment.
  • lint is the category of the suppression comment, and in this case it suppresses the linter.
  • /suspicious/noDebugger or /suspicious: optional, group and name, or group of the rule you want to suppress.
  • (foo): optional, values associated to the suppression comment, these values are used by the specific rules. Refer to the documentation of the single rule to learn if they are used.
  • <explanation> explanation why the rule is disabled.

They disable a lint rule for the next line of code.

In the following example, the suppression comment biome-ignore lint/suspicious/noDebugger: reason will disable the debugger; statement at line 2, but the debugger at line 3 will still raise a diagnostic:

file.js
// biome-ignore lint/suspicious/noDebugger: reason
debugger;
debugger;

They disable a lint rule for an entire file. They must be placed at the top of the file, and they must start with biome-ignore-all.

These suppression comments are very useful when you want to suppression some lint rule for a particular file, and you don’t want to rely to a single configuration override to achieve that.

The following example, the suppression comment biome-ignore-all lint/suspicious/noDebugger: reason will disable the lint rule for the whole file generated.js:

generated.js
// biome-ignore-all lint/suspicious/noDebugger: reason
debugger
debugger

When a top-level suppression comment isn’t at the top of the file, it is considered unused and Biome will emit a diagnostic with category suppression/unused.

They disable a lint rule from a particular line of code, to another line of code, called range.

To mark the beginning of a range suppression, the suppression comment must start with // biome-ignore-start, and to mark the end of it, the suppression comment must start with // biome-ignore-end.

The following example will disable the rule lint/suspicious/noDoubleEquals for line 2 and 3, but the line 5 will raise a diagnostic:

// biome-ignore-start lint/suspicious/noDoubleEquals: reason
a == b;
c == d;
// biome-ignore-end lint/suspicious/noDoubleEquals: reason
f == g;

The range suppression comments use a FILO queue (First in, Last out), which means that the first range suppression encountered by Biome will be the last one to be disabled.

The following example goes more in detail:

  • The debugger statement at line 1 will raise a diagnostic because there’s no suppression comment that disables it.
  • The comment // biome-ignore-start lint/suspicious/noDebugger: reason at line 2 starts disabling noDebugger from line 3 onwards.
  • The comment // biome-ignore-start lint/suspicious/noDoubleEquals: reason at line 3 starts disabling noDoubleEquals from line 4 onwards.
  • The comment // biome-ignore-end lint/suspicious/noDoubleEquals: reason at line 7 terminates the suppression of noDoubleEquals that was started by the suppression comment at line 3.
  • The debugger statement at line 8 doesn’t raise diagnostics due to the suppression comment at line 3.
  • The f == g statement raises a diagnostic because the rule noDoubleEquals isn’t suppressed anymore.
  • The rule noDebugger is disabled for the rest of the file because there isn’t a suppression comment biome-ignore-end that “closes” the suppression comment at line 2.
debugger;
// biome-ignore-start lint/suspicious/noDebugger: reason
debugger
// biome-ignore-start lint/suspicious/noDoubleEquals: reason
a == b;
c == d;
// biome-ignore-end lint/suspicious/noDoubleEquals: reason
debugger
f == g;

The first-class integration with LSP-compatible editors allows you to configure certain aspects of how Biome should behave.

When a violation is detected by Biome, a diagnostic is sent to the editor alongside with an arbitrary number of code actions, that are meant to address the diagnostic. Those actions are:

Usually, by positioning your cursor in the range of the diagnostic and typing a certain shortcut (it varies per editor), a tooltip will appear with the possible code actions.

By default, these actions are always displayed by the editor, however it’s possible to opt-out from them.

Use quickfix.biome to control whether the editor should show the code fix of any rule:

~/.config/zed/settings.json
{
"code_actions_on_format": {
"quickfix.biome": false,
}
}

Alternatively, it’s also possible turn off the code action for a specific rule. Each rule has a code action associated to it that follow the pattern quickfix.biome.<GROUP>.<NAME>.

For example, if you want to turn off the code action of the rule noUnusedVariables, you’ll use quickfix.biome.correctness.noUnusedVariables:

~/.config/zed/settings.json
{
"code_actions_on_format": {
"quickfix.biome.correctness.noUnusedVariables": false,
}
}

Use source.suppressRule.inline.biome to control whether the editor should show the inline suppression code action:

~/.config/zed/settings.json
{
"code_actions_on_format": {
"source.suppressRule.inline.biome": false,
}
}

Use source.suppressRule.topLevel.biome to control whether the editor should show the top-level suppression code action:

~/.config/zed/settings.json
{
"code_actions_on_format": {
"source.suppressRule.topLevel.biome": false,
}
}

Many of Biome lint rules are inspired from other linters. If you want to migrate from other linters such as ESLint or typescript-eslint, check the rules sources page. If you are migrating from ESLint, there’s a dedicated migration guide.

  1. Use the command biome migrate eslint to port the rules defined in your eslint configuration file to biome.json:
    Terminal window
    biome migrate eslint
  2. Lint the project by suppressing possible new rules that are caught by Biome, using the following command:
    Terminal window
    biome lint --write --unsafe --suppress="suppressed due to migration"
    The command will suppress all linting violation that Biome finds, using the reason "suppressed due to migration". Now the linter shouldn’t error anymore, and it’s possible to remove the suppression comments at a later stage.

The linter divides rules under groups. Groups are meant to offer some sort of category which rules falls under. This information becomes useful, for users, when choosing a rule to enable/disable, or for developers when creating new lint rules.

Rules focused on preventing accessibility problems.

Rules that focus on inspecting complex code that could be simplified.

Rules that detect code that is guaranteed to be incorrect or useless.

New rules that are still under development. Nursery rules require explicit opt-in via configuration on stable versions because they may still have bugs or performance problems. They are enabled by default on nightly builds, but as they are unstable their diagnostic severity may be set to either error or warning, depending on whether we intend for the rule to be recommended or not when it eventually gets stabilized. Nursery rules get promoted to other groups once they become stable or may be removed. Rules that belong to this group are not subject to semantic version.

Rules catching ways your code could be written to run faster, or generally be more efficient.

Rules that detect potential security flaws.

Rules enforcing a consistent and idiomatic way of writing your code. By default, these rules will only generate warnings instead of errors.

Rules that detect code that is likely to be incorrect or useless.

Frequently Asked Questions (FAQ)

Section titled Frequently Asked Questions (FAQ)

Why does rule X has an unsafe fix? It seems safe to me.

There are different reasons why the Biome team decides to mark a fix unsafe, but mostly it boils down to the following:

  • The lint rule is still under heavy development, as well as the fix.
  • The rule fix can change the semantics of a program, so the fix must be opted in by the user.
  • The rule fix can deteriorate the DX while typing and/or saving. An example is noUnusedVariables, which adds _ to the name of unused variables. This can deteriorate the DX of programmers while typing and saving.

If a code fix doesn’t follow these three guidelines, it’s possible that the team forgot to make the rule fix safe. Please open an issue or send a PR!