DevLogTechnical writing
Tutorials

Stop Hand-Timing Your Commands: Benchmarking with hyperfine

October 30, 2026

You know the ritual. Mid-refactor, you need to know if the new version of your script is actually faster, so you run time npm run build and get 12.4 s. You run it again: 16.1 s. Again: 13.0 s. Which number is the truth?

None of them. A single run of any command is mostly noise — disk caches, CPU frequency scaling, whatever else your laptop happened to be doing that second. One sample is a rumor. You need a distribution.

That's the gap hyperfine fills. It's a command-line benchmarking tool written in Rust that runs your command many times and reports the mean, the standard deviation, and a heads-up when a run looks like an outlier. Version 2.0.0 landed on October 7, 2026, so this isn't a dusty utility — it's a tool mid-redesign, and the redesign is worth knowing about.

The basics

hyperfine 'sleep 0.3' is enough to get going. It picks its own run count: at least 10 runs, and enough of them to total roughly 3 seconds. If you want a fixed number, hyperfine --runs 20 'npm run build'.

The real payoff is comparison. Pass several commands and it benchmarks them back to back:

hyperfine 'hexdump file' 'xxd file'

The first command is the reference; every later result shows its change and factor against it. That's the difference between "I think it's faster" and a number a reviewer can't argue with.

Making the numbers honest

Two flags matter more than the others. Disk-bound commands lie depending on cache temperature, so:

Also new in 2.0: benchmarked commands run directly, with no intermediate shell, by default. That removes shell startup from the equation — and when you do opt back in with -S for pipes and friends, hyperfine measures the shell's startup time and subtracts it. It is annoyingly thorough, in the best way.

Benchmark one parameter at a time

Threads are the classic case:

hyperfine -P num_threads 1 12 'make -j {num_threads}'

-P scans a numeric range (step size via -D), and -L takes a list of values. A favorite trick from the README: benchmark branches directly.

hyperfine --parameter-list branch main,perf-improvements \
    --setup 'git switch {branch}' 'python main.py'

The branch switch happens in --setup, before timing, so you're measuring the code, not the checkout.

Results you can share

--export-markdown results.md produces a table with mean, change, and factor — perfect for a PR description, which forces whoever touches the code next to see the number. --export-json gives per-run detail, and hyperfine ships Python scripts (plot_histogram, plot_whisker) you can run straight from the repo. If you want it in CI, Bencher consumes hyperfine output to catch regressions on every commit.

Speaking of 2.0: the default report is now wall-clock time plus peak memory, and --metrics can swap in CPU cycles, instruction counts, cache misses, or branch misses on Linux. Note that hardware counters require shell-free mode — another reason the no-shell default is the right call.

The tool is named for the hyperfine levels of caesium-133, the atomic transition that defines the second. Which is a lovely way of saying: it exists to make your timing honest. Stop counting on the stopwatch; let it take the measurement.

Happy benchmarking. That's the gap hyperfine fills. It's a command-line benchmarking tool written in Rust that runs your command many times and reports the mean, the standard deviation, and a heads-up when a run looks like an outlier. Version 2.0.0 landed on October 7, 2026, so this isn't a dusty utility — and its new defaults will surprise you if you learned the 1.x way. The tool is named for the hyperfine levels of caesium-133, the atomic transition that defines the second. It's a lovely way of saying the tool exists to make your timing honest. So stop hand-timing — let hyperfine keep time for you.

← More Tutorials