Self-hosted service
showwin/speedtest-go avatar
showwin/speedtest-go

speedtest-go measures your link against speedtest.net servers

CLI and Go API to Test Internet Speed using speedtest.net

874 stars146 forksGoMIT

At a glance

What is it?
speedtest-go is a Go rewrite of the command line speed test that talks to the same speedtest.net server network, and it ships both a CLI with server selection and a reusable Go package with multi-server and packet loss examples.
Who is it for?
speedtest-go fits a network engineer who wants a scriptable speedtest against the public speedtest.net server pool, a Go developer who wants to embed the measurement in an existing tool, and an operator who needs periodic measurements from a container or a Kubernetes CronJob.
Can I use it commercially?
Yes. MIT 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 47 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The same speedtest.net server network, driven from Go

speedtest-go measures internet speed by talking to the speedtest.net server network, and the interesting part is that it is not a new measurement infrastructure. It is a Go implementation of the same approach that the Python speedtest-cli took, and the README names that project as the inspiration. The pitch is speed: the README claims you can speedtest 2x faster than speedtest.net itself with almost the same result, and points to an experimental results section for the numbers. Whether you accept that claim depends on what you are measuring against, since the result is bounded by the speed of the server you are connected to. The useful framing for an engineer is that this is a client for a known, widely mirrored measurement system, rewritten in a language that starts fast, ships as a single static binary, and can be embedded in other Go programs rather than invoked as a subprocess.

Server selection is a first class part of the CLI

The nearest server is chosen by default, but the flags show that server choice is treated as something the user controls. You can list the public servers, select one or more by id, search them by keyword, filter them by country code with --filter-cc, or bypass the whole discovery step with --custom-url when you have your own endpoint. The README's example of listing servers prints the distance and latency for each candidate alongside the operator name.

bash
$ speedtest --list
Testing From IP: 124.27.199.165 (Fujitsu) [34.9769, 138.3831]
[6691]     9.03km   32.3365ms  Shizuoka (Japan) by sudosan
[6087]   120.55km   51.7453ms  Fussa-shi (Japan) by Allied Telesis Capital Corporation
[6508]   125.44km   54.6683ms  Yokohama (Japan) by at2wn

Multi-server mode is enabled with -m, and the README calls it recommended. The --location flag takes a raw lat,lon pair and --city takes a named city label from a built-in list, with --city-list to print the labels. That combination of a coordinate, a city and a server id means you can pin a measurement to a specific vantage point, which is what makes the tool usable for a comparison over time rather than only a one-off check.

Three output formats and a JSON mode built for pipelines

The CLI writes human-readable output, unix style output, JSON, and JSONL where each line is one JSON object. The JSON modes are the reason to care if you are feeding results into a monitoring system or a spreadsheet. Three output formats exist, but only two are machine friendly. There is also --unix for a script-friendly plain format, and --debug for verbose logging when a test misbehaves.

The measured result includes latency with jitter and min/max values, download and upload throughput with the number of bytes used, and a packet loss figure. The README explains one of the fields specifically: for upload results, `Confirmed` indicates the proportion of uploaded bytes confirmed by a successful upload response, which is how you tell a stalled upload from a slow one. The packet loss analyser runs in the background for up to 30 seconds, so a full run reports loss for a window that extends past the moment the transfer finished, and a script that assumes the process ends the instant throughput is known will need to account for that.

Go package layout for embedding the measurement in your own code

The repository is both a binary and a library, and the go.mod names the module github.com/showwin/speedtest-go. The top level files show the split: speedtest.go at the root, with a speedtest/ directory holding the library, task.go holding task execution, tui.go holding the terminal interface, and separate test files for the package and for the TUI. The examples directory has three separate programs, one named multi, one named naive and one named packet_loss, which tells you the intended integration shapes: a single measurement, a multi-server run, and a packet loss focused run. The CLI itself is built on kingpin, and the module requires kingpin v2.4.0 along with ysmrr for the spinner and progress output, go-colorable, go-isatty and go-runewidth for terminal handling, and golang.org/x/term. The go directive reads 1.26, so the toolchain floor is recent.

Installing through Homebrew, Nix, a release binary, or a container

There are four documented installation paths, and the Homebrew route needs one extra trust step because the formula is not in core.

bash
$ brew tap showwin/speedtest
$ brew trust --formula showwin/speedtest/speedtest
$ brew install speedtest

Nix users can enter an environment with the packaged version.

bash
$ nix-shell -p speedtest-go

For Linux, Windows and other platforms, the README points at the compatible packages on the Releases page. The container route is a multi-architecture build using buildx, and the Dockerfile in the repository is a two stage build on golang:1.27.0-alpine that cross compiles from the target platform, ending on an alpine image with a non-root user called speedtest and bash as the shell. The comment in the Dockerfile explains why the entrypoint is bash rather than the speedtest command itself, so the same image can also be used interactively.

Running the container and scheduling it on Kubernetes

The container runs an interactive shell by default, and the same image takes the speedtest arguments directly.

bash
# Run a basic speedtest
docker run yourusername/speedtest-go:latest speedtest-go

# Run with multiple servers and JSON output
docker run yourusername/speedtest-go:latest speedtest-go --server 6691 --server 6087 --json

# Run with custom location
docker run yourusername/speedtest-go:latest speedtest-go --location=60,-110

The Kubernetes examples in the README cover both shapes you would actually deploy. A bare Pod runs one measurement and exits, with restartPolicy Never, which is right for a job you trigger by hand. A CronJob runs periodically with a schedule of every 6 hours, passes --json so the output can be collected, and uses restartPolicy OnFailure so a transient network failure is retried rather than lost. The CronJob manifest is the more useful of the two for a network team, since a periodic JSON measurement is the form that fits an existing monitoring pipeline.

Where the measurement stops being neutral

Two limitations are structural rather than bugs. The first is that every result inherits the properties of the speedtest.net server network: the server you connect to, its operator, the route between you and it, and the fact that a public server shared with other users is not a dedicated link. The -m multi-server mode and the --filter-cc and --location options reduce the chance of a single unrepresentative server dominating your reading, but they do not turn a public measurement into a lab measurement. The second is resource use. The --saving-mode flag exists for constrained environments and the README describes it as testing with few resources at low accuracy, especially above 30Mbps, which is a candid statement of the accuracy ceiling of the low-resource path. The --thread flag caps concurrent connections with a default cap of 8 and lets upload adapt automatically, so on a link with very many parallel flows you are measuring a configuration choice as much as your bandwidth.

Editorial conclusion

speedtest-go fits a network engineer who wants a scriptable speedtest against the public speedtest.net server pool, a Go developer who wants to embed the measurement in an existing tool, and an operator who needs periodic measurements from a container or a Kubernetes CronJob. It is the wrong tool for a measurement that has to be authoritative, because it inherits the speedtest.net server network, its operator bias and its result variance, and the packet loss analyser runs in the background for up to 30 seconds so a test is not instantaneous. Before adopting it, run speedtest --list to see the servers it can reach from your network, compare a single run against the -m multi-server mode, and check the ping mode you select since the --ping-mode flag supports icmp, tcp and http with different accuracy trade-offs. The last push was on 2026-09-06 and the current release is v1.8.3 from 2026-09-01.

Frequently asked questions

How do I install speedtest-go on macOS?

The README documents a Homebrew route: tap showwin/speedtest, run brew trust --formula showwin/speedtest/speedtest, then brew install speedtest. Nix users can use nix-shell -p speedtest-go, and other platforms download a package from the Releases page.

Which flags does the speedtest-go CLI support?

The help output lists flags for listing servers, selecting server ids, custom URLs, saving mode, JSON and JSONL output, unix format, location and city selection, proxy and source interface binding, multi-server mode, thread count, country code filtering, masking ISP details, ping mode, protocol and units.

Can I use speedtest-go as a Go library?

Yes. The module is github.com/showwin/speedtest-go, with the library code in the speedtest directory and the examples directory containing multi, naive and packet_loss programs that show the intended integration shapes.

How do I run speedtest-go in Docker or Kubernetes?

The README gives buildx commands for a multi-architecture image and docker run examples that pass speedtest-go arguments, plus a Pod manifest and a CronJob manifest that runs a JSON measurement every 6 hours with restartPolicy OnFailure.

What licence and version is speedtest-go released under?

The repository carries an MIT LICENSE file. The current release is v1.8.3 from 2026-09-01, and the last push was on 2026-09-06.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. showwin/speedtest-go on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/showwin-speedtest-go.svg)](https://hysenlabs.com/projects/showwin-speedtest-go)

Was this useful?