ruff-pre-commit: wiring Ruff's linter and formatter into pre-commit
A pre-commit hook for Ruff.
At a glance
- What is it?
- ruff-pre-commit is a standalone repository that delivers two pre-commit hooks: ruff-check for Ruff's linter and ruff-format for its formatter. Hook ordering and --fix interaction are the main configuration details to get right.
- Who is it for?
- Add ruff-pre-commit if you already have a pre-commit setup and want Ruff's linter and formatter enforced on each commit without writing your own hook scripts. Skip it if your team runs ruff check and ruff format in CI alone and has no need for a commit-time gate.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 6, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A standalone repository that delivers Ruff via pinned PyPI wheels
Ruff itself is maintained at astral-sh/ruff. ruff-pre-commit exists as a separate repository for a narrow purpose: the pre-commit framework installs hooks by cloning a repo and running setup, and building Ruff from source would be slow since Ruff is written in Rust. By existing as a standalone project, ruff-pre-commit lets pre-commit install the tool from prebuilt wheels on PyPI rather than compiling anything.
The mechanism is visible in pyproject.toml, which lists ruff==0.16.10 as the only dependency. When pre-commit installs the repository at rev v0.16.10, it installs that pinned wheel into an isolated virtual environment managed by pre-commit. Every developer on the team therefore runs the same Ruff binary, regardless of any globally installed version. This means local ruff versions and CI ruff versions are decoupled from the pre-commit version: only the rev in .pre-commit-config.yaml determines what version runs at commit time.
Version tracking is manual. Updating Ruff means checking the ruff-pre-commit releases page, finding the matching rev, and updating .pre-commit-config.yaml. Pre-commit does have a pre-commit autoupdate command that can automate this step; the README does not document that command, but it is a standard pre-commit feature. Each ruff-pre-commit release matches a Ruff release with the same version number, so tracking one is the same as tracking the other.
The minimal .pre-commit-config.yaml entry for both hooks
Adding both hooks to a project requires a single stanza in .pre-commit-config.yaml. The README gives this as the starting configuration:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.16.10
hooks:
# Run the linter.
- id: ruff-check
# Run the formatter.
- id: ruff-formatThe rev field determines which Ruff version runs. Pinning it explicitly makes behavior reproducible across machines and CI. Both hook IDs reference entries in .pre-commit-hooks.yaml at the repository root, which defines default file types and entry points for each hook.
With this baseline configuration, ruff-check checks staged files for lint violations but does not write any changes, so a staged file with a violation blocks the commit and prints the issues to the terminal. The formatter operates separately: ruff-format rewrites Python source files to match Ruff's formatting style. Python code examples embedded in Markdown files are also processed automatically, with no additional configuration needed. Whether that is desirable depends on whether your project's documentation Markdown contains Python snippets you want kept in consistent style.
Hook order becomes a hard constraint once --fix is present
Without --fix, the two hooks report problems but do not write files. Hook order does not matter because neither hook changes staged files in that mode.
Adding --fix to ruff-check changes that. With --fix active, the linter rewrites staged files to apply corrections. Those rewritten files may not conform to the formatter's style. If ruff-format runs before ruff-check --fix in the pipeline, the formatter applies its style first, and then the linter's rewrite undoes some of those changes, potentially producing output that does not meet the formatter's requirements.
The README frames this ordering rule precisely: with --fix, ruff-check must run before ruff-format and before any other formatting tool that writes to the same staged files. The correct configuration is:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.16.10
hooks:
# Run the linter.
- id: ruff-check
args: [ --fix ]
# Run the formatter.
- id: ruff-formatWhen --fix is absent, the README notes that running ruff format after ruff check is safe, because the formatter is designed to avoid introducing new lint errors, provided the Ruff configuration does not include rules that conflict with the formatter's output. A specific set of linter rules creates such conflicts, and the Ruff formatter documentation lists which rules to avoid or suppress for a clean ruff check / ruff format combination.
Passing rule flags through args, with commas requiring quoted strings
Rule selection and deselection go through the args key, which passes flags directly to ruff check at the command line. The README gives this example:
hooks:
- id: ruff-check
args: [ --fix, "--extend-select=I,E", "--ignore=F401" ]Any flag accepted by ruff check is valid in args. The quoting behavior shown above is a YAML parsing requirement rather than a Ruff requirement. Inline YAML lists use commas as list separators. A value like --extend-select=I,E without quotes causes the YAML parser to split on the comma, passing --extend-select=I and E as two separate arguments rather than one flag with a comma-separated value. Quoting the argument wraps the comma inside the string and prevents that split.
Rule configuration that spans many selects or controls Ruff's overall behavior fits better in a pyproject.toml or ruff.toml file, where Ruff reads it automatically for any invocation including the pre-commit hook. What goes in args is typically a small override: an extra rule category for commit-time enforcement, a suppression for a rule that triggers during development but not in CI, or a flag that is specifically meaningful in the pre-commit context. Using args for the entire Ruff configuration creates a maintenance burden, since changes to the rules need updating in .pre-commit-config.yaml instead of the central Ruff config file.
Jupyter Notebooks are included by default; pyproject.toml and Quarto need version guards
By default, ruff-check processes Python files, pyi stub files, and Jupyter Notebooks. To exclude Jupyter Notebooks from the linter, types_or must be specified explicitly to omit jupyter:
hooks:
- id: ruff-check
types_or: [ python, pyi ]
args: [ --fix ]
- id: ruff-format
types_or: [ python, pyi, markdown ]Adding pyproject.toml linting requires including pyproject in types_or for ruff-check. It also requires identify>=2.6.18, which is the pre-commit file-type identification library. If the installed version of identify is older than 2.6.18, the pyproject type is not recognized and pyproject.toml files are silently skipped.
Quarto document support adds one more version requirement: identify>=2.6.20 for the quarto file type. Quarto also needs a Ruff setting to map the qmd extension to the markdown file type, which is set in the Ruff configuration rather than in .pre-commit-config.yaml. Without that Ruff-side mapping, Quarto files will not be processed even with the correct types_or entry.
prek.toml as an alternative if you prefer TOML configuration
The README documents a second configuration path using prek, a hook runner by j178 that reads prek.toml instead of .pre-commit-config.yaml. The same hook repository and the same hook IDs work:
[[repos]]
repo = "https://github.com/astral-sh/ruff-pre-commit"
rev = "v0.16.10" # Ruff version.
hooks = [
# Run the linter.
{ id = "ruff-check", args = ["--fix"], types_or = ["python", "pyi"] },
# Run the formatter.
{ id = "ruff-format", types_or = ["python", "pyi", "markdown"] },
]The hook order rule carries over: the README explicitly refers the reader to the pre-commit guidance on hook order when using prek with --fix. The two configuration files express the same information in different syntax, and both point to the same ruff-pre-commit repository at the same rev.
Prek is not bundled with or required by ruff-pre-commit. It is an alternative runner mentioned for teams that already use prek or prefer TOML-first tooling. Teams on standard pre-commit have no reason to switch.
Dual licence, weekly release cadence, and the main Ruff repository for bug reports
ruff-pre-commit is dual-licensed under Apache License 2.0 and MIT. Both licence texts appear in the repository as LICENSE-APACHE and LICENSE-MIT. Either licence is available at the user's option. Contributions are dually licensed under both, which is the standard pattern for projects in the Rust and Python ecosystems that want to maximize compatibility with downstream users.
Release cadence tracks Ruff: v0.16.10 on 2026-10-01, v0.16.9 on 2026-09-24, v0.16.8 on 2026-09-16. The weekly pace reflects Ruff's own shipping schedule. The last push to the ruff-pre-commit repository was on 2026-10-05, and the repository is not archived. Teams that require a stable, slow-moving revision may want to stay on a specific rev rather than following every weekly release.
Bug reports about linting or formatting behavior do not belong in this repository. ruff-pre-commit is a delivery mechanism. If ruff-check misidentifies a valid construct as a violation, or ruff-format produces unexpected output, the correct place to file the report is the main astral-sh/ruff issue tracker. This repository's job is to expose those tools through pre-commit, not to implement the tools themselves.
Editorial conclusion
Add ruff-pre-commit if you already have a pre-commit setup and want Ruff's linter and formatter enforced on each commit without writing your own hook scripts. Skip it if your team runs ruff check and ruff format in CI alone and has no need for a commit-time gate. Before adopting, pin rev to v0.16.10, decide whether to include --fix (which requires placing ruff-check before ruff-format in the config), and check the linter-formatter incompatibilities page in the Ruff documentation if you use a custom rule select list.
Frequently asked questions
How do I add ruff-pre-commit to my project?
Add a repos entry to .pre-commit-config.yaml pointing to https://github.com/astral-sh/ruff-pre-commit with rev set to v0.16.10, then list the ruff-check and ruff-format hook IDs under hooks.
What is the difference between ruff-check and ruff-format in ruff-pre-commit?
ruff-check runs Ruff's linter and optionally applies fixes with --fix. ruff-format runs Ruff's formatter, including formatting Python code blocks in Markdown files by default.
Does ruff-pre-commit support Jupyter Notebooks?
By default, ruff-check runs against Python, pyi, and Jupyter Notebook files. To exclude notebooks, override types_or to only list python and pyi. Adding pyproject.toml linting requires identify>=2.6.18.
What licence does ruff-pre-commit use?
ruff-pre-commit is dual-licensed under Apache License 2.0 and MIT. Users may choose either, and both licence files are in the repository.
Must ruff-check run before ruff-format?
Only when using --fix. The README states that with --fix active, ruff-check must come before ruff-format and before other formatting tools. Without --fix, the order does not matter.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/astral-sh-ruff-pre-commit)