Skip to content

Benchmarks

These benchmarks compare hk, lefthook, pre-commit, and prek running 10 linters on a synthetic project. Since lefthook's parallel: true mode has race conditions when linters touch overlapping files, we run lefthook in safe (sequential) mode—the only correct option. pre-commit and prek both run hooks sequentially.

hk is the only tool that runs linters in parallel and safely.

See Why hk? for context on why these differences exist.

Setup

A synthetic project with ~6,000 files across multiple languages:

  • 4000 Python, 500 JavaScript/TypeScript, 500 JSON, 500 Shell, 250 YAML, 200 CSS, 200 Markdown

Ten linters with overlapping file coverage:

LinterFilesHow hk avoids write locks
prettier*.{js,ts,css,md}check_list_files — only locks files that need fixing
eslint*.{js,ts}Falls back to write lock (eslint has no diff/list mode)
black*.pycheck_diff — hk applies the diff itself
ruff check*.pyCheck only — read lock
ruff format*.pycheck_diff — hk applies the diff itself
jq*.jsoncheck_diff
yq*.{yml,yaml}check_diff
shfmt*.{sh,bash}check_diff
trailing-whitespace* (all files)check_diff via hk util (built-in Rust)
newlines* (all files)check_diff via hk util (built-in Rust)

The trailing-whitespace and newlines linters use **/* globs—they overlap with every other linter. pre-commit and prek always run hooks sequentially. lefthook supports parallel: true but has no file-level coordination, so overlapping linters cause race conditions—we run it in safe (sequential) mode. hk is the only tool that runs everything in parallel safely, using file-level read/write locks.

Results

Benchmark results

Reproducing

Everything is in the benchmark/ directory.

Prerequisites

bash
mise use hyperfine lefthook prettier eslint shfmt jq yq
uv tool install pre-commit prek black ruff

Generate and run

bash
# Generate a synthetic project (~700 files)
benchmark/generate-project.sh /tmp/hk-bench

# Run benchmarks
benchmark/run.sh /tmp/hk-bench

# Customize
NUM_JS=500 NUM_PY=500 benchmark/generate-project.sh /tmp/hk-bench
RUNS=20 WARMUP=3 benchmark/run.sh /tmp/hk-bench

Results are saved as JSON in benchmark/results/ and both a chart and data file are generated in docs/public/.

Licensed under the MIT License. Maintained by @jdx and friends.