CLI
One binary, ninety seconds, every number on this site
A static Go binary with no dependencies, no daemon and no account. Point it at a fresh VPS and get a shareable JSON report.
Install
with Go 1.26+
go install github.com/niklas-schmidt-dev/providerbench/cmd/providerbench@latestor build from source
git clone https://github.com/niklas-schmidt-dev/providerbench
cd providerbench && go build -o providerbench ./cmd/providerbenchRun
full run with a shareable report
providerbench run \
--provider hetzner --product cloud-vps --plan cax21 \
--region fsn1 --price 7.55 --env os_image=ubuntu-24.04 \
--json report.jsonpick your tests, go faster
providerbench run --quick -t cpu,steal # 20 seconds: compute + overselling only
providerbench run -t disk --dir /mnt/data # benchmark a specific volume
providerbench list # every available test
providerbench system # detected hardware & virtualizationFor honest numbers: use a fresh instance, run at least twice at different times of day, and run nothing else while measuring. The disk test writes a 1 GiB file in the working directory (or --dir) and removes it afterwards.
Extend it
Every test implements one interface and registers itself. Adding a benchmark — PostgreSQL transactions, Redis ops, S3 upload speed, LLM time-to-first-token — is one file.
internal/tests/mytest.go
package tests
import (
"context"
"github.com/niklas-schmidt-dev/providerbench/internal/bench"
)
func init() { bench.Register(myTest{}) }
type myTest struct{}
func (myTest) Name() string { return "mytest" }
func (myTest) Description() string { return "what this measures, one line" }
func (myTest) Run(ctx context.Context, opts Options) (*bench.Result, error) {
res := newResult("mytest")
// ... measure something ...
res.Add("my_metric", 42.0, "ops/s", true) // name, value, unit, higher-is-better
finish(res)
return res, ctx.Err()
}That's the whole contract. The test now shows up in providerbench list, runs with everything else, and lands in the JSON report.