CLI tool
lance0/xfr avatar
lance0/xfr

xfr: a Rust network bandwidth tester with a live TUI, QUIC and MPTCP

A modern iperf3 alternative with a live TUI, multi-client server, and QUIC support. Built in Rust.

546 stars21 forksRustApache-2.0

At a glance

What is it?
xfr is a Rust alternative to iperf3 that measures TCP, UDP, QUIC and Linux MPTCP throughput with a live terminal interface, parallel streams, JSON and CSV output, LAN discovery and Prometheus metrics. It suits a network engineer who wants a modern replacement for iperf3, and it uses its own protocol, so it does not interoperate with iperf3 servers.
Who is it for?
xfr fits a network engineer who wants a maintained bandwidth tool with QUIC and MPTCP transports, machine-readable output and Prometheus metrics rather than the ageing iperf3, and it does not fit a workflow that depends on talking to existing iperf3 servers, since the protocol is its own.
Can I use it commercially?
Yes. Apache-2.0 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 2 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

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

Editorial analysis

An iperf3 replacement that will not talk to iperf3

xfr is a modern iperf3 alternative with a live TUI, a multi-client server, MPTCP and QUIC support, built in Rust.

The compatibility position is stated without ambiguity: xfr uses its own protocol and does not connect to iperf3 servers. The readme also says to use the same xfr version on both peers for all current features. So this is a replacement in the workflow sense, in the sense that it occupies the same slot in your testing script, and not a wire-compatible replacement.

The quick start shows the shape of the tool.

bash
cargo install xfr            # Rust 1.88+; or brew install lance0/tap/xfr
xfr serve                    # On the server
xfr 192.168.1.1              # On the client: TCP, 10 seconds
xfr 192.168.1.1 -P 4         # Four parallel streams
xfr 192.168.1.1 -u -b 1G     # UDP at 1 Gbps

Five commands and five options, and each one maps onto a concept. xfr serve runs the listener, a bare host argument runs a TCP test for ten seconds, -P sets the number of parallel streams, and -u with -b switches to UDP at a specified bitrate.

The last of those is the important one for anyone diagnosing a network, because UDP is where throughput tests stop being simple. A UDP test at a fixed bitrate is not measuring capacity, it is measuring what happens when you push a known rate at the link and watch for loss. The readme's table of use cases makes that explicit, with a task to detect UDP congestion at 500 Mbps over 60 seconds and a separate task to find a path's UDP payload limit with the --probe-mtu flag.

The firewall requirement is one line that will save you a debugging session. Allow port 5201 for TCP and UDP, and see the firewall requirements section for older peers and client source ports.

The project is licensed MIT or Apache-2.0, the default branch is master, the last push was on 2026-10-18, and the recent releases are v0.12.0 on 2026-10-18, v0.11.0 on 2026-10-13 and v0.10.1 on 2026-09-04.

The TUI is the main difference from iperf3

The feature list leads with the client-side terminal interface: a live TUI with throughput graphs and per-stream statistics. The readme ships a demo recording at docs/demo.gif described as showing the live TUI with a real-time throughput graph, per-second stats and settings.

A graph of throughput over time is a genuinely different instrument from a final average. A TCP transfer that reports 900 Mbps on average may have spent its first two seconds at 100 Mbps while the congestion window filled, and it may have collapsed to 50 Mbps at the end. None of that shows up in the summary line that iperf3 prints, and all of it is exactly what you need to know when you are looking at a slow link.

The server side has the same treatment with a dashboard, started with xfr serve --tui. That makes it a multi-client server as well as a single-target tester: you can point several clients at one machine and watch the aggregate and per-client traffic live.

Both interfaces report status through OSC 7501, and unsupported terminals ignore it. That is the terminal's standard channel for reporting a title or an icon, so the TUI can set the window title to the current state without depending on a terminal-specific escape sequence, and terminals that do not understand it simply show nothing extra.

The key bindings are documented per interface. Pressing ? or F1 gives TUI help, and the client keys include s for settings, t for themes and p to pause and resume traffic. Themes are configurable, and the separate client and server keybinding references are in docs/FEATURES.md.

Pause and resume is worth a second look, because it is the kind of control that turns a benchmark tool into an investigation tool. Being able to stop the traffic and look at something, then start it again, is what you want when you are checking whether a link behaves differently under load and at rest.

Transports, output formats and the tasks the tool covers

The transport list is TCP, UDP, QUIC and Linux MPTCP, with parallel streams and bidirectional tests supported. The output formats are plain text, JSON, streaming JSON and CSV, and the remaining features are saved configuration, LAN discovery, result comparison and optional Prometheus metrics.

Four of the supported transports are worth distinguishing. TCP is the baseline. UDP gives you loss and congestion behaviour at a fixed offered rate. QUIC is a different protocol with its own handshake and congestion control, so it measures something TCP cannot. And MPTCP is a Linux kernel feature that allows multiple paths for one connection, which is what makes it useful for bonded links and for testing whether a path is actually multipath-capable.

The table of real-world tasks is where the tool's scope becomes concrete.

That is the VPN tunnel task, xfr 10.8.0.1 -t 30s. The bidirectional options are -R for reverse and --bidir for both directions at once, which matters because a link that is fast one way and slow the other is a common and easily missed finding.

The UDP congestion detection case is xfr <host> -u -b 500M -t 60s. And --probe-mtu finds a path's UDP payload limit, which is the test you want when a protocol works with small packets and fails with large ones.

For repeated measurements, results can be saved and compared. Save with -o before.json and -o after.json, then run xfr diff before.json after.json --threshold 5, which compares two runs and reports a change above the given threshold. That is the mechanism for answering whether a change to your network actually helped.

For finding a target on a local network, xfr discover does LAN discovery, which uses mDNS according to the dependency list.

For automation, the readme points at the scripting documentation covering Docker, CI/CD and Prometheus, and the Prometheus support is an optional cargo feature rather than something always compiled in.

Installing it, and what is not qualified

The installation section lists many channels, and the readme makes a distinction that is unusual and worth repeating.

The primary route is cargo install xfr, which needs Rust 1.88 or later, and there is a second form that adds the metrics support with the --features prometheus flag. Homebrew is the alternative for macOS and Linux with brew install lance0/tap/xfr.

bash
cargo install xfr                       # Default features
cargo install xfr --features prometheus # Add metrics support
brew install lance0/tap/xfr             # macOS/Linux

Beyond those two, the installation document covers release binaries, Docker, AUR, Termux, Nix, pkgsrc and source builds, plus shell completions.

The platform story has a caveat that most projects would not print. Release binaries cover Linux x86_64 and ARM64, macOS Apple Silicon, and Android ARM64. macOS Intel can build from crates.io, and NetBSD has a community pkgsrc package. Native Windows remains experimental, and WSL2 is recommended.

Then the sentence that shows the project's care: CI covers Ubuntu, macOS and Windows, but packaging and CI coverage do not establish runtime qualification for every platform or transport. See the platform details and limitations section.

That is a distinction most projects blur. A binary that compiles on Windows is not the same as a benchmark whose results you can trust on Windows, and the readme declines to claim the second from the first.

The project also publishes a comparison and migration guide at docs/COMPARISON.md, which is the document to read if you have an existing iperf3 workflow and want to know what changes. And there is a KNOWN_ISSUES.md alongside a ROADMAP.md, a SECURITY.md and a CHANGELOG.md at the top level.

The examples directory contains a config.toml and a grafana-dashboard.json, which tells you that the Prometheus path is meant to feed a real dashboard rather than just a metrics endpoint.

Security, and the defaults you should change before exposing a server

The readme has a security section that is short and unusually direct, and it should be read before you run a server anywhere reachable.

TCP and UDP bulk payloads are plaintext. QUIC encrypts traffic but verifies peer identity only when a PSK is configured. And the guidance is to prefer the --psk-file option over placing a key in command arguments or environment variables.

That last point is a small operational rule with real value. A PSK passed as a command argument appears in the process list and in shell history, and an environment variable is inherited by every child process and can leak through crash reports or diagnostics tooling. A file path keeps the secret in a file with permissions you control.

The readme points at three documents before you expose a server: the transport security details and the authentication requirements in the feature documentation, and the security policy file.

There are also separate sections on network considerations, denial of service protections and server resource usage, which tells you the project has thought about the fact that a bandwidth test server is an attractive thing to point at someone else's machine.

The trusted contributor list in the acknowledgements is unusual for a tool of this size. The readme gives special thanks to Matthieu Baerts, a Linux kernel MPTCP co-maintainer, for extensive testing, detailed bug reports with packet traces and feature suggestions including MPTCP support, kernel TCP pacing, zero-copy IO and high stream-count hardening. The project says xfr is significantly better because of those contributions.

That is worth noting for what it tells you about the MPTCP implementation in particular. A feature implemented with a kernel co-maintainer sending packet traces is a different proposition from one written from documentation, and it is the reason the MPTCP path is in the tool at all.

Editorial conclusion

xfr fits a network engineer who wants a maintained bandwidth tool with QUIC and MPTCP transports, machine-readable output and Prometheus metrics rather than the ageing iperf3, and it does not fit a workflow that depends on talking to existing iperf3 servers, since the protocol is its own. Before running it on an exposed host, read the transport security section, because TCP and UDP payloads are plaintext and QUIC verifies peer identity only when a PSK is configured, and allow port 5201 for TCP and UDP on both peers.

Frequently asked questions

Can xfr connect to an iperf3 server?

No. xfr uses its own protocol and does not connect to iperf3 servers, and the readme says to use the same xfr version on both peers for all current features. There is a comparison and migration guide at docs/COMPARISON.md for moving an existing workflow across.

Which transports does xfr support?

TCP, UDP, QUIC and Linux MPTCP, with parallel streams and bidirectional tests on top of them. QUIC encrypts traffic but verifies peer identity only when a PSK is configured, and TCP and UDP payloads are plaintext.

How do I install xfr and what are the platform limits?

Run cargo install xfr with Rust 1.88 or later, optionally with --features prometheus, or use brew install lance0/tap/xfr. Release binaries cover Linux x86_64 and ARM64, macOS Apple Silicon and Android ARM64, and native Windows remains experimental with WSL2 recommended.

How do I compare two xfr test results?

Save each run with -o before.json and -o after.json, then run xfr diff before.json after.json --threshold 5. The threshold is the change you want reported rather than noise.

Official sources

  1. Issues
  2. lance0/xfr on GitHub
  3. License: Apache-2.0
  4. README
  5. Releases
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/lance0-xfr.svg)](https://hysenlabs.com/projects/lance0-xfr)

Was this useful?