toxiproxy

A TCP proxy for injecting network and system failures to test how applications handle unreliable dependencies.

Tool
Go
vv2.12.0
12,305stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
75/100Good
Development Activity72
Maintenance48
Community80
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
77/100Good
Architecture78
Code Quality85
Innovation75
Learning Curve68

Toxiproxy is a TCP proxy built by Shopify to simulate network and system failure conditions in testing, CI, and development environments. Rather than relying on ad hoc tools like tc or iptables that require root and aren’t cross-platform, teams route their application’s connections (databases, caches, downstream services) through Toxiproxy and then inject latency, bandwidth caps, timeouts, connection resets, and outright outages on demand through a simple HTTP API.

Because the toxics are controlled dynamically at runtime, tests can flip a dependency’s failure mode on and off around a single assertion, proving a service degrades gracefully instead of raising an uncaught exception. Shopify has run Toxiproxy in its own test suites since 2014, and the project ships official Go and Ruby clients alongside a large list of community clients for other languages.

What You Get

  • Standalone proxy daemon - toxiproxy-server runs as a long-lived process (or Docker container) that transparently forwards TCP traffic between a client and an upstream.
  • HTTP control API - every proxy and toxic is created, updated, and deleted through a JSON API on port 8474, so toxics can be toggled from inside a test without touching a config file.
  • toxiproxy-cli - a companion CLI (toxiproxy-cli create, toxiproxy-cli toxic add) for scripting proxies and toxics from shell scripts or ad hoc debugging sessions.
  • Official Go client library - the client package in this module wraps the HTTP API in idiomatic Go (NewClient, CreateProxy, AddToxic) for use directly in Go test suites.
  • Nine built-in toxics - latency, down, bandwidth, slow_close, timeout, reset_peer, slicer, limit_data, and packet_loss cover the failure modes teams hit most often in production.
  • Prometheus metrics - optional proxy- and runtime-level metrics exposed on /metrics for observing toxic behavior during load or chaos runs.

Common Use Cases

  • Resiliency test suites - assert that an application degrades gracefully (returns cached data, retries, times out cleanly) when a database or cache becomes slow or unavailable.
  • Chaos engineering in CI - inject latency or packet loss into service-to-service calls in an integration environment to catch timeout and retry bugs before they reach production.
  • Local development against flaky dependencies - simulate a slow third-party API locally to verify timeout and circuit-breaker configuration without waiting for a real outage.
  • Load and failure testing pipelines - combine Toxiproxy’s HTTP API with existing test or load-testing tooling to script multi-stage failure scenarios, such as ramping up latency before dropping the connection.

Under The Hood

Architecture Toxiproxy’s core is organized around a small set of collaborating types in the root package: ApiServer (api.go) owns a ProxyCollection and exposes the mux-routed HTTP API; each Proxy (proxy.go) owns a net.Listener, a ConnectionList of live net.Conns, and a ToxicCollection (toxic_collection.go) that stores per-direction, ordered toxic chains; incoming connections are wired into Links (link.go) that pipe bytes from client to upstream (and back) through stream wrappers built from the stream package (io_chan.go, direction.go), with each toxics.Toxic implementation (toxics/*.go — latency, bandwidth, slicer, etc.) inserted as a stage in that pipe so it can delay, truncate, or drop data as it flows through. The cmd/server and cmd/cli binaries are thin main packages that construct an ApiServer or a client.Client respectively and call into the shared root/client packages, so the actual proxying and API logic lives in one place regardless of which binary is running. A change to the core Proxy/Link streaming abstraction would ripple into every toxic implementation and the metrics collectors, since they all assume the same channel-based stream.Direction plumbing.

Tech Stack The module targets Go 1.23 and depends on gorilla/mux for HTTP routing, rs/zerolog for structured logging, prometheus/client_golang for optional metrics collection, urfave/cli/v2 for the toxiproxy-cli command surface, golang.org/x/term for TTY detection in colored CLI output, and gopkg.in/tomb.v1 for goroutine lifecycle management inside each Proxy. Cross-platform releases (Linux/macOS/Windows, Homebrew, MacPorts, .deb packages, Docker images published to GHCR) are produced with a Makefile and goreleaser, and CI runs on GitHub Actions with a dedicated static-analysis workflow enforcing style via .golangci.yml. There is no database — state is entirely in-memory per running toxiproxy-server process, optionally seeded from a JSON config file at startup.

Code Quality Nearly every source file in the root package, client/, toxics/, and stream/ packages has a matching _test.go file (proxy_test.go, api_test.go, client_test.go, latency_test.go, packet_loss_test.go, and more), using Go’s standard testing package with table-driven tests and a testhelper package providing a fixture for spinning up real TCP servers under test — a strong sign the project tests actual socket behavior rather than mocking it away. Error handling is idiomatic Go, with explicit error returns wrapped via fmt.Errorf("...: %w", err) in the client and API layers, naming is consistent, and a dedicated CI workflow runs static analysis on every push in addition to the test suite. Types model API payloads directly (Proxy, Toxic, ApiError structs with JSON tags) rather than passing around untyped maps.

API Design The public surface is deliberately small and consistent: client.NewClient(endpoint) returns a *Client with a handful of verbs (CreateProxy, Proxy, Populate, ResetState) that mirror the HTTP API one-to-one, and each returned *Proxy exposes toxic manipulation (AddToxic, UpdateToxic, RemoveToxic, Disable/Enable, Save, Delete) as methods on the object itself rather than free functions taking IDs, so call sites read naturally in test code. Getting started requires only a running binary and a two-line client import; the tradeoff is that toxic Attributes are passed as an untyped map rather than typed structs per toxic, so attribute names and types are only caught at runtime — the project’s CREATING_TOXICS.md and worked examples largely compensate by documenting every toxic’s expected attributes.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search