Skip to content

Git Hooks

Git allows executing scripts during the run of a git command using Git Hooks. For example, you can format and lint the staged files before committing or pushing. Several tools exist to simplify the management of Git Hooks. In the following sections we introduce some of them and how they can be used with Biome.

Lefthook provides a fast, cross-platform, and dependency-free hook manager. It can be installed via NPM.

Add a file named lefthook.yml at the root of your Git repository. Some examples of Lefthook configurations:

  • Check formatting and lint before committing

    lefthook.yml
    pre-commit:
    commands:
    check:
    glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
    run: npx @biomejs/biome check --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}
  • Format, lint, and apply safe code fixes before committing

    lefthook.yml
    pre-commit:
    commands:
    check:
    glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
    run: npx @biomejs/biome check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files}
    stage_fixed: true

    stage_fixed: true adds again the staged files.

  • Check formatting and lint before pushing

    lefthook.yml
    pre-push:
    commands:
    check:
    glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}"
    run: npx @biomejs/biome check --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {push_files}

Note that you don’t need to use both glob and --files-ignore-unknown=true. Using only --files-ignore-unknown=true allows handling files supported in the present and in the future by Biome. If you wish more control over which files are handled, you should use glob.

--no-errors-on-unmatched silents possible errors in case no files are processed.

Once configured, run lefthook install to set up the hooks.

Husky is a widely-used hook manager in the JavaScript ecosystem. Husky doesn’t hide unstaged changes and is not able to provide the list of staged files. This is why it is often used in tandem with another tool such as lint-staged or git-format-staged.

If your project contains a package.json, you can automatically set up husky hooks upon package installation using scripts.prepare:

package.json
{
"scripts": {
"prepare": "husky"
}
}

lint-staged is one of the most used tools in the JavaScript ecosystem.

Add the following husky configuration:

.husky/pre-commit
lint-staged

The configuration of lint-staged is directly embedded in package.json. Here’s some example of commands that you could find useful when running the Git hooks:

package.json
{
"lint-staged": {
// Run Biome on staged files that have the following extensions: js, ts, jsx, tsx, json and jsonc
"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": [
"biome check --files-ignore-unknown=true", // Check formatting and lint
"biome check --write --no-errors-on-unmatched", // Format, sort imports, lint, and apply safe fixes
"biome check --write --organize-imports-enabled=false --no-errors-on-unmatched", // format and apply safe fixes
"biome check --write --unsafe --no-errors-on-unmatched", // Format, sort imports, lints, apply safe/unsafe fixes
"biome format --write --no-errors-on-unmatched", // Format
"biome lint --write --no-errors-on-unmatched", // Lint and apply safe fixes
],
// Alternatively you can pass every files and ignore unknown extensions
"*": [
"biome check --no-errors-on-unmatched --files-ignore-unknown=true", // Check formatting and lint
]
}
}

Remember to use the CLI option --no-errors-on-unmatched in your command, to silent possible errors in case no files are processed.

In contrast to other tools such as lefthook, pre-commit, and lint-staged, git-format-staged doesn’t use git stash internally. This avoids manual intervention when conflicts arise between unstaged changes and updated staged changes. See the comparison of git-format-staged with other tools.

Some examples of configuration:

  • Check formatting and lint before committing

    .husky/pre-commit
    git-format-staged --formatter 'biome check --files-ignore-unknown=true --no-errors-on-unmatched \"{}\"' .
  • Format, lint, and apply safe code fixes before committing

    .husky/pre-commit
    git-format-staged --formatter 'biome check --write --files-ignore-unknown=true --no-errors-on-unmatched \"{}\"' .

pre-commit provides a multi-language hook manager. Biome provides four pre-commit hooks via the biomejs/pre-commit repository.

hook iddescription
biome-ciCheck formatting, check if imports are organized, and lints
biome-checkFormat, organize imports, lint, and apply safe fixes to the committed files
biome-formatFormat the committed files
biome-lintLint and apply safe fixes to the committed files

In the following example, we assume that you installed pre-commit and run pre-commit install in your repository. if you want to use the biome-check hook, add the following pre-commit configuration to the root of your project in a file named .pre-commit-config.yaml:

.pre-commit-config.yaml
repos:
- repo: https://github.com/biomejs/pre-commit
rev: "v0.1.0" # Use the sha / tag you want to point at
hooks:
- id: biome-check
additional_dependencies: ["@biomejs/biome@1.4.1"]

This will run biome check --write when you run git commit.

Note that you must specify which version of Biome to use thanks to the additional_dependencies option. pre-commit separately installs tools and need to know which one to install.

If Biome is already installed as a npm package in your local repository, then it can be a burden to update both package.json and .pre-commit-config.yaml when you update Biome. Instead of using the provided Biome hooks, you can specify your own local hook.

For example, if you use npm, you can write the following hook in .pre-commit-config.yaml:

.pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: local-biome-check
name: biome check
entry: npx @biomejs/biome check --write --files-ignore-unknown=true --no-errors-on-unmatched
language: system
types: [text]
files: "\\.(jsx?|tsx?|c(js|ts)|m(js|ts)|d\\.(ts|cts|mts)|jsonc?)$"

The pre-commit option files is optional, because Biome is able to ignore unknown files (using the option --files-ignore-unknown=true).

You can also use a custom shell script. Note that you can encounter cross-platform incompatibilities. We recommend the use of a dedicated tool as the one presented in the previous sections.

Some examples of shells scripts:

  • Check formatting and lint before committing

    .git/hooks/pre-commit
    #!/bin/sh
    set -eu
    npx @biomejs/biome check --staged --files-ignore-unknown=true --no-errors-on-unmatched
  • Format, lint, and apply safe code fixes before committing

    .git/hooks/pre-commit
    #!/bin/sh
    set -eu
    if git status --short | grep --quiet '^MM'; then
    printf '%s\n' "ERROR: Some staged files have unstaged changes" >&2
    exit 1;
    fi
    npx @biomejs/biome check --write --staged --files-ignore-unknown=true --no-errors-on-unmatched
    git update-index --again

    Note that we make the hook fail if staged files have unstaged changes.