Back to Biomejs

Biome v2.4—Embedded Snippets, HTML Accessibility, and Better Framework Support

src/content/docs/blog/biome-v2-4.mdx

latest27.3 KB
Original Source

import Avatar from "@/components/Avatar.astro"; import EditorSettings from "@/components/EditorSettings.astro"; import Contributor from "@/components/Contributor.astro";

Biome v2.4 is the first minor release of the year! After more than ten patches from v2.3, today we bring to you a new version that contains many new features!

Once you have upgraded to Biome v2.4.0, migrate your Biome configuration to the new version by running the migrate command:

shell
biome migrate --write

Highlights

Among all the features shipped in this release, here are the ones we think you're going to like most!

Embedded snippets in JavaScript

One of the most significant new features in Biome 2.4 is the ability to format and lint embedded CSS and GraphQL snippets within JavaScript files. Enable this experimental feature to automatically format and lint CSS and GraphQL code within template literals.

Biome recognizes CSS snippets from styled-components, Emotion, and similar CSS-in-JS libraries:

js
import styled from "styled-components";

const Foo = styled.div`
  display: flex;
  color: red;
`;

GraphQL queries and mutations within JavaScript are now properly formatted and linted:

js
import gql from "graphql-tag";

const PeopleCountQuery = gql`
  query PeopleCount {
    allPeople {
      totalCount
    }
  }
`;

To enable these features, add this to your configuration:

json
{
  "javascript": {
    "experimentalEmbeddedSnippetsEnabled": true
  }
}

:::note Snippets with interpolations are not yet supported. :::

Editor inline configuration

Editors can now inject a Biome configuration to the Biome Language Server without affecting the project's configuration.

If you have a Biome extension compatible with your LSP-ready editor, you can map inlineConfig. The configuration will be merged with the project's configuration and it will take precedence.

In the following example, the editor won't emit any diagnostics for the rule noConsole, but the CLI will still conform to the configuration of the project.

<EditorSettings zed={{ name: "inline_config", value: { "linter": { "rules": { "suspicious": { "noConsole": "off" } }, } }, }} vsCode={{ name: "inlineConfig", value: { "linter": { "rules": { "suspicious": { "noConsole": "off" } }, } }, }} />

Major improvements to HTML-ish languages

In Biome v2.3, we announced experimental full support for HTML-ish languages such as Vue, Svelte, and Astro. We've since focused on improving the developer experience based on community feedback. Several improvements were shipped in patch releases.

Biome 2.4 brings significantly improved parsing for Vue and Svelte, resulting in better formatting across the board. Additionally, the rules noUnusedVariables, useConst, useImportType and noUnusedImports have been substantially improved, so you will see fewer false positives.

All these improvements are visible only when the flag html.experimentalFullSupportEnabled is set to true. If you previously used the overrides configuration workaround to disable certain rules, you can now remove it. If you encounter false positives, please report them in this issue. We now have the infrastructure to address these problems.

The CSS parser can now parse Vue SFC syntax such as :slotted, :deep, and v-bind(), as well as :global and :local inside .astro, .svelte and .vue files.

HTML accessibility rules

Biome 2.4 introduces 15 comprehensive accessibility-focused lint rules for HTML, helping you build more accessible web applications:

These rules work seamlessly with Vue, Svelte, and Astro files. Please help us to ship more a11y rules.

Rule profiler

The commands lint and check now have a --profile-rules flag. This flag enables the new internal profiler, which allows you to capture the execution time of lint rules, assist actions, and GritQL plugins.

The profiler tracks only the execution time of the rule, and it doesn't track the time spent in querying Biome's CST. The flag will print an output similar to this one:

txt
Rule execution time (does not include any preprocessing)
  total       avg         min         max         count rule
    42.069ms     1.010µs    41.000ns   227.625µs  41633  correctness/noUnusedVariables
    23.131ms   452.000ns    42.000ns   330.750µs  51096  suspicious/noFocusedTests
     9.864ms   193.000ns     0.000ns   149.375µs  51046  suspicious/noConsole
     8.074ms   198.000ns     0.000ns   141.208µs  40721  correctness/noUnusedFunctionParameters
     7.963ms   137.000ns     0.000ns   263.958µs  57899  style/useNodejsImportProtocol
     6.711ms     4.355µs    41.000ns   686.000µs   1541  source/organizeImports
     4.076ms   664.000ns     0.000ns   132.792µs   6130  correctness/noUnusedImports
     4.015ms    55.000ns     0.000ns   131.250µs  72343  correctness/noTypeOnlyImportAttributes
     3.320ms   524.000ns     0.000ns   115.791µs   6334  style/useImportType
   384.101µs   164.000ns     0.000ns    74.875µs   2328  correctness/noNodejsModules
   384.042µs     2.782µs    42.000ns   163.417µs    138  correctness/noDuplicatePrivateClassMembers
    10.753µs   282.000ns    83.000ns   833.000ns     38  correctness/noSuperWithoutExtends

One way to interpret the data is to check the rules/actions that have low counts, and check their execution time. For example, if the execution time feels way too high compared to what it should be, maybe it's a good place to look for possible optimizations. Since we landed this feature, we have found some bottlenecks that we have fixed since then.

Configuration file discovery

Biome 2.4 improves configuration file discovery in two major ways:

  1. Hidden configuration files: Biome now loads .biome.json and .biome.jsonc files. The loading order is: biome.jsonbiome.jsonc.biome.json.biome.jsonc

  2. Config home directories: Biome now attempts to load configuration files from platform-specific config directories:

    • $XDG_CONFIG_HOME or $HOME/.config/biome on Linux
    • /Users/$USER/Library/Application Support/biome on macOS
    • C:\Users\$USER\AppData\Roaming\biome\config on Windows

The priority order is: project folder (working directory) → parent folders → config home.

Linter and Assist

New Assist Actions

Remove Duplicate CSS Classes

Biome 2.4 introduces the noDuplicateClasses assist action to detect and remove duplicate CSS classes.

For JSX files: Supports class, className attributes and utility functions like clsx, cn, cva.

For HTML files: Checks class attributes. This is the first assist action for HTML.

jsx
// Before
<div class="flex p-4 flex" />;

// After
<div class="flex p-4" />;

Thank you <Contributor handle="mldangelo" />.

Sort Interface Members

Added a new assist action useSortedInterfaceMembers that sorts TypeScript interface members for improved readability. It includes an autofix.

Before:

ts
interface MixedMembers {
  z: string;
  a: number;
  (): void;
  y: boolean;
}

After:

ts
interface MixedMembers {
  a: number;
  y: boolean;
  z: string;
  (): void;
}

Enhanced Lint Rules

useSortedKeys with groupByNesting Option

Added groupByNesting option to the useSortedKeys assist. When enabled, object keys are grouped by their value's nesting depth before sorting alphabetically.

Simple values (primitives, single-line arrays, and single-line objects) are sorted first, followed by nested values (multi-line arrays and multi-line objects).

json
{
  "assist": {
    "actions": {
      "source": {
        "useSortedKeys": {
          "level": "on",
          "options": {
            "groupByNesting": true
          }
        }
      }
    }
  }
}

useHookAtTopLevel with ignore Option

Added ignore option to the useHookAtTopLevel rule. You can now specify function names that should not be treated as hooks, even if they follow the use* naming convention.

json
{
  "linter": {
    "rules": {
      "correctness": {
        "useHookAtTopLevel": {
          "options": {
            "ignore": ["useDebounce", "useCustomUtility"]
          }
        }
      }
    }
  }
}

useIterableCallbackReturn with checkForEach Option

The rule useIterableCallbackReturn now supports a checkForEach option. When set to false, the rule will skip checking for forEach() callbacks for returning values.

Improved useHookAtTopLevel Detection

Updated useHookAtTopLevel to better catch invalid hook usage. The rule now generates diagnostics if:

  • A hook is used at the module level (top of the file, outside any function)
  • A hook is used within a function or method which is not a hook or component, unless it is a function expression (such as arrow functions commonly used in tests)

useImportExtensions with Custom Mappings

Added the extensionMappings option to useImportExtensions. This allows you to specify custom file extensions for different module types. For example, to ban all .ts imports in favor of .js imports:

json
{
  "linter": {
    "rules": {
      "nursery": {
        "useImportExtensions": {
          "level": "error",
          "options": {
            "extensionMappings": {
              "ts": "js"
            }
          }
        }
      }
    }
  }
}

useUnifiedTypeSignatures Enhancements

Added 2 options from typescript-eslint to useUnifiedTypeSignatures:

  • ignoreDifferentlyNamedParameters - Ignores overload signatures whose parameter names differ
  • ignoreDifferentJsDoc - Ignores overload signatures whose JSDoc comments differ

Ignore Options for CSS Rules

Added ignore option to noUnknownProperty, noUnknownFunction, noUnknownPseudoClass, and noUnknownPseudoElement. If an unknown property/function/selector name matches any of the items provided in ignore, a diagnostic won't be emitted.

Improved Svelte Variables Detection

Improved the rule noUnusedVariables in Svelte files by correctly detecting variables defined in the JavaScript blocks and used inside the templates.

New Linter Domain: types

Biome 2.4 introduces a new linter domain called types. This domain enables all rules that require the type inference engine to function.

As opposed to the project domain (which only enables rules that require the module graph), the types domain specifically targets rules that need type information.

The following nursery rules have been moved to the types domain:

  • useArraySortCompare
  • useAwaitThenable
  • useFind
  • useRegexpExec
  • noUnnecessaryConditions
  • noMisusedPromises
  • noFloatingPromises

This allows you to enable or disable type-based linting more granularly using the --only and --skip flags.

Biome 2.4 promotes 24 nursery rules to stable groups, making them production-ready.

Correctness Rules

Promoted the following rules to the correctness group:

Suspicious Rules

Promoted the following rules to the suspicious group:

Complexity Rules

Promoted the following rules to the complexity group:

Style Rules

Promoted the following rules to the style group:

Formatter

Embedded Snippets Formatting

Biome 2.4 can now format embedded CSS and GraphQL snippets within JavaScript files. See the Embedded snippets in JavaScript section in Highlights for details and examples.

Trailing Newline Option

Added the formatter option trailingNewline. When set to false, the formatter will remove the trailing newline at the end of formatted files. The default value is true, which preserves the current behavior.

This option is available globally and for each language-specific formatter configuration:

json
{
  "formatter": {
    "trailingNewline": false
  },
  "javascript": {
    "formatter": {
      "trailingNewline": true
    }
  }
}

CLI flags are also available: --formatter-trailing-newline, --javascript-formatter-trailing-newline, --json-formatter-trailing-newline, etc.

:::caution Setting trailingNewline to false can cause issues in certain environments and tools. Many POSIX-compliant tools and text editors expect files to end with a newline character. Removing the trailing newline may result in:

  • Warnings or errors from compilers and interpreters
  • Issues with shell scripts that may not process the last line correctly
  • Problems with version control systems showing unnecessary diff changes
  • Incompatibility with coding standards that require POSIX-compliant text files

We recommend keeping the default value of true unless you have a specific requirement to remove trailing newlines. :::

Top-Level Suppression Comments

Added support for the top-level suppression comment biome-ignore-all format: <explanation>. When placed at the beginning of the document, Biome won't format the code.

js
// biome-ignore-all format: generated

const a = [];
const b = [];

Formatting Applied with Code Fixes

Formatting is now applied when applying safe/unsafe fixes via biome check. This ensures your code is properly formatted after applying automated fixes.

CSS Parser Improvements

CSS @function At-Rule Support

Added support for parsing and formatting the CSS @function at-rule from the CSS Mixins Module Level 1 specification:

css
@function --transparent(--color <color>, --alpha <number>: 0.5) returns <color> {
  result: oklch(from var(--color) l c h / var(--alpha));
}

CSS Modules Auto-Detection

Biome now automatically enables CSS modules parsing for *.module.css files. If your codebase only uses *.module.css files, you can remove the manual parser configuration.

CSS Properties Ordering Update

Updated the CSS properties ordering to align with stylelint-config-recess-order v7.4.0, adding support for containment properties, font synthesis properties, ruby properties, color adjustment properties, view transitions properties, shapes properties, motion path properties, and more.

CSS Module Syntax in Vue/Svelte/Astro

Added support for parsing :global and :local inside .astro, .svelte and .vue files, in the <style> portion of the file. This capability is only available when experimentalFullHtmlSupportEnabled is set to true.

CLI

Enhanced --skip and --only Flags

Added --only and --skip options to biome check and biome ci, covering both lint diagnostics and assist actions. You can now run or exclude specific:

  • Lint rules
  • Assist actions
  • Groups of rules and actions
  • Domains (including the new types domain)

Examples:

shell
biome check --only=suspicious/noDebugger src/**/*.js
biome ci --skip=project src/**
biome lint --only=types  # Run only type-based rules

Multiple Reporters and Reporter Output to Files

Biome 2.4 adds support for multiple reporters and the ability to save reporter output to arbitrary files.

Combine Multiple Reporters in CI

If you run Biome on GitHub, you can now use both the default reporter and the GitHub reporter:

shell
biome ci --reporter=default --reporter=github

Save Reporter Output to a File

With the new --reporter-file CLI option, it's now possible to save the output of all reporters to a file:

shell
biome ci --reporter=rdjson --reporter-file=/etc/tmp/report.json
biome ci --reporter=summary --reporter-file=./reports/file.txt

You can combine these two features. For example, have the default reporter written on terminal, and the rdjson reporter written on file:

shell
biome ci --reporter=default --reporter=rdjson --reporter-file=/etc/tmp/report.json

The --reporter and --reporter-file flags must appear next to each other.

New SARIF Reporter

Added a new reporter --reporter=sarif, that emits diagnostics using the SARIF format. This is particularly useful for integrating Biome with security and code quality platforms.

shell
biome ci --reporter=sarif --reporter-file=biome-results.sarif

File Watcher Control

Added new CLI options to the commands lsp-proxy and start that allow control over the Biome file watcher:

  • --watcher-kind (env: BIOME_WATCHER_KIND): Controls how the Biome file watcher behaves. Options: recommended (default), polling, or none.
  • --watcher-polling-interval (env: BIOME_WATCHER_POLLING_INTERVAL): The polling interval in milliseconds when using polling mode (defaults to 2000ms).

Enhanced Logging Options

Revamped the logging options for all Biome commands. The commands format, lint, check, ci, search, lsp-proxy and start now accept consistent logging CLI options with environment variable aliases:

  • --log-file (env: BIOME_LOG_FILE) - Optional path/file to redirect log messages to
  • --log-prefix-name (env: BIOME_LOG_PREFIX_NAME) - Allows changing the prefix applied to the file name of the logs (daemon only)
  • --log-path (env: BIOME_LOG_PATH) - Allows changing the folder where logs are stored (daemon only)
  • --log-level (env: BIOME_LOG_LEVEL) - The level of logging: debug, info, warn, error, or none
  • --log-kind (env: BIOME_LOG_KIND) - What the log should look like

Stacktrace for Fatal Errors

It's now possible to provide the stacktrace for a fatal error. The stacktrace is only available when the environment variable RUST_BACKTRACE=1 is set:

shell
RUST_BACKTRACE=1 biome lint

Additional Features

GritQL JSON Support

Added JSON as a target language for GritQL pattern matching. You can now write Grit plugins for JSON files, enabling:

  • Searching and transforming JSON configuration files
  • Enforcing patterns in package.json and other JSON configs
  • Writing custom lint rules for JSON using GritQL

Example patterns:

Match all key-value pairs:

grit
language json
pair(key = $k, value = $v)

Match objects with specific structure:

grit
language json
JsonObjectValue()

Supports both native Biome AST names (JsonMember, JsonObjectValue) and TreeSitter-compatible names (pair, object, array) for compatibility with existing Grit patterns.

For more details, see the GritQL documentation.

LSP and Editor Features

LSP Progress Reporting

The Biome Language Server now reports progress while scanning files and dependencies in the project, providing better feedback during long-running operations.

Configuration and Editor Support

Cursor Files Support

Added support for Cursor files. When Biome sees a Cursor JSON file, it will parse it with comments enabled and trailing commas enabled:

  • $PROJECT/.cursor/
  • %APPDATA%\Cursor\User\ on Windows
  • ~/Library/Application Support/Cursor/User/ on macOS
  • ~/.config/Cursor/User/ on Linux

Other Improvements

Vue SFC CSS Syntax Support

The Biome CSS parser is now able to parse Vue SFC syntax such as :slotted, :deep, and v-bind(). These pseudo-functions and directives are only correctly parsed when the CSS is defined inside .vue components.

This capability is only available when experimentalFullHtmlSupportEnabled is set to true.

e18e ESLint Plugin Support

Added e18e ESLint plugin as a recognized rule source. Six Biome rules now reference their e18e equivalents: useAtIndex, useExponentiationOperator, noPrototypeBuiltins, useDateNow, useSpread, and useObjectSpread.

More Improvements

In addition to the features highlighted above, Biome 2.4 includes numerous bug fixes, performance improvements, and smaller enhancements across the toolchain. For a complete list of changes, refer to the changelog page.

I like where this is going, how can I help?

I want to remind you that Biome is a project led by volunteers who like programming, open-source, and embrace the Biome philosophy, so any help is welcome.

Translations

If you are familiar with Biome and would like to contribute to its outreach, you can assist us by translating the website into your native language. In this dashboard, you can check the supported languages and if they are up-to-date.

Chat with us

Join our Discord server, and engage with the community. Chatting with the community and being part of the community is a form of contribution.

Code contributions

If you like the technical aspects of the project, and you want to make your way into the Rust language, or practice your knowledge around parsers, compilers, analysers, etc., Biome is the project for you!

There are numerous aspects to explore; I assure you that you won't get bored. Here is a small list of the things you can start with:

Financial help

If you believe in the future of the project, you can also help with a financial contribution, via Open Collective or GitHub Sponsors.

Additionally, the project provides an enterprise support program where you as a company can employ one of the core contributors to work a specific aspect of the Biome toolchain.