# Toxiproxy: a TCP proxy for deterministic network fault injection in tests

> Toxiproxy is a Go TCP proxy plus an HTTP control API that lets tests cut, delay and corrupt connections on demand. It fits CI and integration suites, not production traffic.

**Shopify/toxiproxy** — :alarm_clock: :fire: A TCP proxy to simulate network and system conditions for chaos and resiliency testing

- Repository: https://github.com/Shopify/toxiproxy
- Website: https://github.com/shopify/toxiproxy
- Stars: 12,371 · Forks: 512
- Language: Go
- License: MIT
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/shopify-toxiproxy

## What Toxiproxy is and the problem it removes

The README states the goal plainly: prove with tests that an application has no single points of failure. That is a narrower job than general chaos engineering. The target user is a developer or CI pipeline that wants a Redis or MySQL outage to be reproducible inside a unit test, not a random event in a staging cluster.

The design constraint that shaped the project is documented under "Why yet another chaotic TCP proxy?": existing tools such as nc are not cross-platform and require root, which the authors found problematic in test, development and CI environments. Toxiproxy is a userspace TCP proxy. It needs no root, runs on a laptop, and exposes an HTTP API so a test can turn a dependency off and back on around a block of code. That is the whole value proposition: failure injection that is a function call, not an infrastructure change.

## Two processes, one HTTP control plane

Toxiproxy is split into two parts, and the split matters when you deploy it. The repository contains a TCP proxy written in Go, and clients talk to that proxy over HTTP. The README describes the flow: configure your application so test connections go through Toxiproxy, then manipulate their health via HTTP.

A proxy is a named mapping from a listen address to an upstream address. In the Rails example, name is toxiproxy_test_redis_tags, listen is 127.0.0.1:22222, upstream is 127.0.0.1:6379. The application connects to 22222; Toxiproxy forwards to the real Redis on 6379. Faults are attached to that mapping as toxics, each with a type, a stream direction and attributes. The README lists latency, down, bandwidth, slow_close, timeout, reset_peer, slicer, limit_data and packet_loss. The Ruby client example applies 1000ms of latency on the downstream stream, and a down toxic makes the connection throw.

Because control is HTTP, the proxy and the test do not have to share a process. That is convenient for CI, where a container can hold the proxy while the test suite drives it. It also means proxy state is server-wide: a proxy created by one test is visible to every other test pointed at that server, so parallel suites need distinct names or distinct servers.

## Installing the server and running a first toxic

The README points to the releases page for binaries and the repository ships a Makefile target that builds both binaries from source. The Dockerfile is built FROM scratch, exposes port 8474, and runs the server with -host=0.0.0.0 by default, with LOG_LEVEL set to info. If you build from source, make build writes ./dist/toxiproxy-server and ./dist/toxiproxy-cli.

Run the server first. The Dockerfile's default command binds it to all interfaces on 8474, which is the port the HTTP API listens on.

```dockerfile
FROM scratch

EXPOSE 8474
ENTRYPOINT ["/toxiproxy"]
CMD ["-host=0.0.0.0"]

ENV LOG_LEVEL=info
```

With the server up, the README's Ruby client populates a proxy that listens on 127.0.0.1:22222 and forwards to Redis on 127.0.0.1:6379, then a test can take that Redis down for the duration of a block.

```ruby
require 'toxiproxy'

Toxiproxy.populate([
  {
    name: "toxiproxy_test_redis_tags",
    listen: "127.0.0.1:22222",
    upstream: "127.0.0.1:6379"
  }
])
```

Point the test client at 127.0.0.1:22222 instead of 6379. To end the experiment, the README's client wraps the toxic in a block that removes it when the block exits; the repository also ships toxiproxy-cli, which wraps the same HTTP endpoints for interactive use per the CLI Example section.

## Where Toxiproxy is the wrong instrument

Toxiproxy only understands TCP connections. It cannot inspect HTTP status codes, retry headers, DNS behaviour or TLS certificate failures, and it has no notion of a request. If your failure mode is "the API returns 503 with a Retry-After header", a TCP proxy is the wrong layer; you want a mock server or a service mesh fault rule.

A second boundary is scope. The README frames the tool for testing, CI and development environments, and the project's own rationale is that it avoids root and cross-platform problems in those environments. Nothing in the repository describes running it in front of production traffic, and the Dockerfile's default binding to 0.0.0.0 on port 8474 is an unauthenticated control plane. Exposing that port beyond a test network lets anything on the network create proxies and cut connections.

A third limitation is statefulness. Toxics are attached to a live proxy mapping, so a test that forgets to remove one leaves the fault in place for every subsequent test against the same server. The README's block-based client API exists precisely to scope a toxic to a closure, and the raw HTTP calls have no such guarantee.

## Toxiproxy compared with a general chaos platform

The closest alternative in kind is a chaos engineering platform such as Chaos Mesh or Gremlin, which injects faults at the kernel, pod or node level. The difference is where the fault lives. A chaos platform manipulates the network namespace or the container runtime, so it can affect traffic your process never routes through a proxy, and it can target a whole service rather than one connection.

Toxiproxy inverts that. It only affects connections you deliberately point at its listen port, which is a real cost: your application must accept a host and port override for every dependency you want to break. The payoff is determinism and locality. There is no cluster, no daemon on the host network, and the fault is removed by an HTTP DELETE. For a unit test that asserts an empty array when Redis is unreachable, that trade is worth it. For proving that a Kubernetes service survives a node failure, it is not.

Within the TCP-proxy category, Toxiproxy's distinguishing feature is the dynamic HTTP API. The README's own comparison is against nc and similar tools, which cannot be reconfigured mid-test.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-15. Recent releases are v2.12.0 on 2025-03-18, v2.11.0 on 2024-10-16 and v2.10.0 on 2024-10-08, so the release cadence is measured in months rather than weeks. The module path is github.com/Shopify/toxiproxy/v2 and go.mod requires Go 1.23.0, which is the constraint to check if you build the server yourself rather than pulling a release binary. The README documents an "Upgrading from Toxiproxy 1.x" subsection, so the 1.x to 2.x move is a real migration the project chose to write down; going forward, the /v2 module path means major-version breaks arrive as a new import path rather than a silent change.

The licence is MIT, which permits commercial use and modification with the copyright notice retained. That is a permissive baseline, not legal advice; if you redistribute the binaries inside a product, read the LICENSE file in the repository rather than this summary. The client libraries live in separate repositories under different maintainers, so their licences and release schedules are independent of the server's.

## Conclusion

Adopt Toxiproxy if your integration suite needs deterministic, per-connection failure injection and you can route test traffic through a local proxy port. Do not adopt it as a production traffic shaper or as a substitute for testing against real network faults in staging. Before committing, verify two things in your own environment: that your client library accepts a custom host and port for every dependency you plan to toxic, and that the proxy mapping survives your test runner's process model, since a proxy registered by one process is visible to the whole server on port 8474.

## FAQ

### What is Toxiproxy?

It is a framework for simulating network conditions, made of a TCP proxy written in Go and a client that talks to the proxy over HTTP. The README describes it as built for testing, CI and development environments, with deterministic tampering plus support for randomized chaos.

### How do I use Toxiproxy in a test?

Configure the application to route its test connections through a Toxiproxy listen port, then change the connection's health over HTTP. The README's example creates a proxy named toxiproxy_test_redis_tags listening on 127.0.0.1:22222 with upstream 127.0.0.1:6379, then applies a down toxic around the code under test.

### What is Toxiproxy for?

Its stated purpose is proving with tests that an application has no single points of failure. The README says Shopify has used it in all development and test environments since October 2014.

## Sources

- [License: MIT](https://github.com/Shopify/toxiproxy/blob/main/LICENSE)
- [Project website](https://github.com/shopify/toxiproxy)
- [README](https://github.com/Shopify/toxiproxy/blob/main/README.md)
- [Releases](https://github.com/Shopify/toxiproxy/releases)
- [Shopify/toxiproxy on GitHub](https://github.com/Shopify/toxiproxy)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/shopify-toxiproxy
