Properly configure `typos` in `pre-commit-hooks.nix`

Published by Philipp Schuster on

typos is the new shining star in the sky of source code spell checkers. pre-commit-hooks.nix is a seamless integration of git hooks with Nix. And we can combine both of them!

Update 2024-01-16: Unfortunately, the whole story is more complicated than anticipated. Follow the upstream discussion for more details. I am going to update this blog post once the upstream discussion is resolved.

Update 2024-01-12: I just contributed the pass_filenames = false option as default in pre-commit-hooks.nix. Now, you don’t have to set this property manually.

Original Post: Unfortunately, the official documentation/README is not as good as it can be.. code is documentation 🙃. So here’s my solution to show you how to integrate typos nicely with a proper configuration. The basic typos.enable = true is not sufficient nor brings a nice user experience or the expected result, unfortunately.

Usually, you have a .typos.toml in your repository, and you want to use it of course from the pre-commit hooks. typos is intended to be run once on the whole tree and not be invoked each time for every single file (unlike other formatters, spell checkers, or similar tooling, which is the default behavior expected by the pre-commit utility). This can be prevented with the pass_filenames = false setting.

So the following code snippet shows my solution (broken down to what’s relevant). For simplicity, the code snipped uses a Nix channel to fetch nixpkgs:

  pkgs = import <nixpkgs> { };
  # Commit ID from 2024-01-08
  pre-commit-hooks = import (builtins.fetchTarball "");
# Configured with the module options defined in `modules/pre-commit.nix`: {
  src = ./.;

  # Set the pkgs to get the tools for the hooks from.
  tools = pkgs;

  hooks = {
    typos = {
      enable = true;
      # `typos` is supposed to be run on the tree. This process may be 
      # restricted by the configuration file. If we don't disable this setting, 
      # typos is invoked with every single file as argument, which makes the 
      # whole process very slow and memory consuming, plus the ignores of the
      # `.typos.toml` are not taken into account.
      pass_filenames = false;

  settings = {
    typos = {
      # This path appears in the generated `.pre-commit-config.yaml` when you follow
      # the shellHook integration in the official
      configPath = ".typos.toml";

So, in the end, it’s fairly easy. However, it would have taken me so much less time with proper documentation or examples.

Philipp Schuster

Hi, I'm Philipp and interested in Computer Science. I especially like low level development, making ugly things nice, and de-mystify "low level magic".


Leave a Reply

Your email address will not be published. Required fields are marked *