RepoPilotOpen in app →

tower-rs/tower

async fn(Request) -> Result<Response, Error>

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2mo ago
  • 55+ active contributors
  • Distributed ownership (top contributor 13% of recent commits)
Show all 6 evidence items →
  • MIT licensed
  • CI configured
  • Tests present

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/tower-rs/tower)](https://repopilot.app/r/tower-rs/tower)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/tower-rs/tower on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: tower-rs/tower

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/tower-rs/tower shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 2mo ago
  • 55+ active contributors
  • Distributed ownership (top contributor 13% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live tower-rs/tower repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/tower-rs/tower.

What it runs against: a local clone of tower-rs/tower — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in tower-rs/tower | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 102 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>tower-rs/tower</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of tower-rs/tower. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/tower-rs/tower.git
#   cd tower
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of tower-rs/tower and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "tower-rs/tower(\\.git)?\\b" \\
  && ok "origin remote is tower-rs/tower" \\
  || miss "origin remote is not tower-rs/tower (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "tower-service/src/lib.rs" \\
  && ok "tower-service/src/lib.rs" \\
  || miss "missing critical file: tower-service/src/lib.rs"
test -f "tower-layer/src/lib.rs" \\
  && ok "tower-layer/src/lib.rs" \\
  || miss "missing critical file: tower-layer/src/lib.rs"
test -f "tower/src/lib.rs" \\
  && ok "tower/src/lib.rs" \\
  || miss "missing critical file: tower/src/lib.rs"
test -f "tower/src/builder/mod.rs" \\
  && ok "tower/src/builder/mod.rs" \\
  || miss "missing critical file: tower/src/builder/mod.rs"
test -f "tower/src/make/make_service.rs" \\
  && ok "tower/src/make/make_service.rs" \\
  || miss "missing critical file: tower/src/make/make_service.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 102 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~72d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/tower-rs/tower"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Tower is a Rust library for composing asynchronous networking services using a modular middleware pattern based on the core Service trait: async fn(Request) -> Result<Response, Error>. It provides reusable, protocol-agnostic components (layers, middleware, balancing, timeouts) for building robust clients and servers by stacking layers of functionality over a base service. Monorepo organized as workspace (Cargo.toml lists 4 members): tower-service/ defines the core Service trait, tower-layer/ provides Layer composition primitives (stack.rs, layer_fn.rs, identity.rs), tower/ contains concrete middleware (balance/, likely util/, timeout/, etc. in src/), and tower-test/ provides mock/macros for testing services. Examples in tower/examples/ demonstrate real usage patterns like tower-balance.rs.

👥Who it's for

Rust systems engineers and library authors building networked applications (HTTP servers, RPC clients, load balancers, proxies) who want to compose middleware without framework lock-in; maintainers of async Rust libraries like Hyper and Tonic that need extensibility through middleware composition.

🌱Maturity & risk

Production-ready and actively maintained. The workspace spans 4 crates (tower, tower-layer, tower-service, tower-test) with MIT licensing, CI workflows in .github/workflows/, MSRV policy of 6+ months (currently 1.64.0), and ~483k lines of Rust. The modular design and long-standing adoption in the Rust web ecosystem indicates stability, though active development suggests ongoing improvements rather than dormancy.

Low structural risk but moderate maintenance overhead: workspace spans 4 separate crates requiring coordinated releases, MSRV policy means regular Rust version bump testing, and dependency on evolving async ecosystem (tokio, futures) means breakage possible on minor version updates. Single-crate failure (e.g., tower-service) would cascade to dependents, so test coverage for trait bounds is critical.

Active areas of work

Active maintenance is evident from CI workflows (CI.yml, publish.yml, release.yml), changelog files in each crate, and structured release process. Specific recent work not visible in file listing, but presence of guides/building-a-middleware-from-scratch.md and comprehensive examples suggests focus on developer experience and documentation.

🚀Get running

git clone https://github.com/tower-rs/tower.git
cd tower
cargo build
cargo test --all
cargo doc --open

Then explore examples: cargo run --example tower-balance --manifest-path tower/Cargo.toml

Daily commands: Tower is a library, not a runnable application. Run tests and examples: cargo test --all for unit tests, cargo run --example tower-balance --manifest-path tower/Cargo.toml for a concrete balance example. Documentation available via cargo doc --open (requires rustdoc generation).

🗺️Map of the codebase

  • tower-service/src/lib.rs — Defines the core Service trait—the fundamental abstraction that all Tower components implement; every middleware and layer builds on this.
  • tower-layer/src/lib.rs — Defines the Layer trait used to compose and wrap Services; essential for understanding how middleware chains are constructed.
  • tower/src/lib.rs — Main crate entry point that re-exports all middleware modules (buffer, limit, balance, filter, etc.) and provides the public API.
  • tower/src/builder/mod.rs — ServiceBuilder pattern for ergonomic composition of layers; shows the idiomatic way to stack middleware in Tower.
  • tower/src/make/make_service.rs — MakeService abstraction for creating per-connection Service instances; critical for server implementations that need per-client state.
  • tower/src/buffer/mod.rs — Buffered service with backpressure handling; one of the most commonly used middleware for async request/response decoupling.
  • tower/src/limit/concurrency/mod.rs — Concurrency limiting middleware; demonstrates how to apply backpressure and prevent service overload.

🧩Components & responsibilities

  • Service trait (async/await, Future, poll()) — Accepts Request, returns Future<Result<Response, Error>>; represents the core request/response handler contract.

🛠️How to make changes

Add a Custom Middleware

  1. Create a new module in tower/src/ (e.g., tower/src/my_middleware/mod.rs) with a Service wrapper struct (tower/src/my_middleware/mod.rs)
  2. Implement the Service trait from tower-service/src/lib.rs, wrapping a generic inner service S (tower-service/src/lib.rs)
  3. Create a Layer in tower/src/my_middleware/layer.rs that implements Layer<S> from tower-layer/src/lib.rs (tower-layer/src/lib.rs)
  4. Export your layer from tower/src/lib.rs so users can compose it with ServiceBuilder (tower/src/lib.rs)
  5. Test with tower-test mock service and verify ServiceBuilder integration works (tower-test/src/mock/mod.rs)

Add a New Load Metric for Adaptive Balancing

  1. Create a new load metric module in tower/src/load/ following the pattern of peak_ewma.rs or pending_requests.rs (tower/src/load/peak_ewma.rs)
  2. Implement the Load trait from tower/src/load/mod.rs with cost() and saturate() methods (tower/src/load/mod.rs)
  3. Integrate with tower/src/balance/p2c/service.rs to use the new metric in choose_index() (tower/src/balance/p2c/service.rs)
  4. Export from tower/src/lib.rs and add tests in tower/src/balance/p2c/test.rs (tower/src/lib.rs)

Implement a Service with Tower

  1. Depend on tower-service crate and implement the Service trait with your request/response types (tower-service/src/lib.rs)
  2. Use ServiceBuilder from tower/src/builder/mod.rs to wrap your service with logging, rate limiting, concurrency limits, etc. (tower/src/builder/mod.rs)
  3. For servers handling multiple connections, implement MakeService from tower/src/make/make_service.rs (tower/src/make/make_service.rs)
  4. Test with tower-test mock utilities to verify middleware behavior in isolation (tower-test/src/lib.rs)

🔧Why these technologies

  • Async/await with Tokio — Tower services are async-first (async fn(Request) -> Result<Response, Error>); Tokio provides the runtime and utilities for concurrent, non-blocking I/O.
  • Pin and Future traits — Tower services return Futures; Pin enables safe self-referential async code and the Service trait is Future-agnostic via poll() semantics.
  • Trait-based composition (Service, Layer) — Tower uses generic trait composition rather than concrete inheritance; enables zero-cost middleware stacking and compile-time type safety.
  • EWMA load metrics — Exponentially weighted moving averages provide low-overhead, responsive load estimation without allocating full histograms per service instance.

⚖️Trade-offs already made

  • Service trait uses poll() instead of async/await

    • Why: Allows Tower to be runtime-agnostic and integrate with any executor; provides lower-level control for complex middleware.
    • Consequence: More verbose than async fn; requires Future boxing in some cases; steeper learning curve for async Rust newcomers.
  • Per-connection MakeService pattern instead of global singleton

    • Why: Enables per-client state, connection pooling per endpoint, and proper resource cleanup without shared locks.
    • Consequence: Server code must implement MakeService; slightly more boilerplate than stateless services.
  • Separate tower, tower-layer, tower-service crates

    • Why: Allows minimal dependencies for service consumers; tower-service is small and stable; tower adds opt-in heavyweight middleware.
    • Consequence: Slightly more complex workspace; requires understanding crate boundaries.
  • Buffer middleware with async queue

    • Why: Decouples bursty clients from slower backends; enables backpressure without blocking.
    • Consequence: Adds memory overhead and latency; not suitable for latency-critical paths.

🚫Non-goals (don't propose these)

  • Does not provide HTTP/gRPC protocol implementations—Tower is protocol-agnostic and works with any request/response types.
  • Does not include server/client network I/O—integrates with tokio, hyper, tonic, etc. for actual socket handling.
  • Does not enforce authentication or authorization—middleware can be layered on top but Tower provides no built-in security primitives.
  • Does not provide persistent storage, caching, or databases—Tower is in-memory middleware for request forwarding and rate limiting.

🪤Traps & gotchas

  1. Service trait is generic over Request/Response/Error types—mismatched generics between layers cause cryptic compile errors; always check trait bounds in middleware. 2) Layer/Service composition order matters and can be non-obvious (applied bottom-to-top); test layer ordering with mock services. 3) MSRV is 1.64.0 but depends on newer features in futures/tokio; check Cargo.toml for each crate's individual MSRV if targeting older Rust. 4) No built-in async runtime—examples assume tokio but Tower itself is runtime-agnostic; don't assume tokio features in tower-layer or tower-service.

🏗️Architecture

💡Concepts to learn

  • Tower Service Trait — The core abstraction unifying all Tower components; understanding the Service trait contract (ready(), call(), poll_ready()) is mandatory before writing any middleware
  • Layer Pattern (Composable Middleware) — Tower's unique contribution: Layer trait allows middleware to be composed without tight coupling, enabling reusable, stackable request/response filters independent of protocol
  • Backpressure via poll_ready() — Tower services explicitly signal readiness via poll_ready() before accepting requests, enabling flow control and preventing resource exhaustion in async systems
  • Pin and Unpin for Futures — Tower services must handle Futures that may be moved in memory; pin-project-lite solves this safely, and misunderstanding Pin causes soundness bugs in custom middleware
  • Error Propagation in Tower Services — Tower services are Result<Response, Error> types; middleware can transform, recover, or propagate errors; understanding error trait bounds prevents type mismatch bugs
  • Load Balancing Strategies (e.g., Least Request, Round-Robin) — tower/src/balance/ implements real load-balancing middleware showing how to maintain state across service calls and select endpoints; instructive for building stateful middleware
  • Async Traits and Generics (impl Trait vs dyn Trait) — Tower heavily uses generic Service<Req> types and async trait methods; conflicting impl/dyn trait choices cause compilation errors; familiarity with trait objects is essential
  • hyperium/hyper — HTTP client/server using Tower's Service trait as foundational abstraction; primary consumer of Tower's middleware patterns
  • tokio-rs/tokio — Async runtime Tower depends on; Tower services are designed to run on tokio executors
  • tonic-rs/tonic — gRPC framework built on Tower Service trait; demonstrates Tower in protocol-specific context (protobuf + HTTP/2)
  • tower-rs/tower-http — HTTP-specific middleware (compression, trace, cors) extending Tower's core abstractions for web use cases
  • rust-lang/futures-rs — Foundation for Tower's async Future composition; Tower Service wraps Futures provided by this crate

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for tower/src/balance/p2c (Power of Two Choices) load balancer

The P2C balance implementation spans multiple files (layer.rs, make.rs, service.rs, test.rs) but test.rs appears minimal. Tower users heavily rely on correct load balancing behavior. A new contributor could add integration tests covering: fairness across unequal service latencies, recovery when services fail/recover, and interaction with the buffer middleware (tower/src/buffer). This would prevent regressions in a critical component.

  • [ ] Review existing test.rs in tower/src/balance/p2c/test.rs to understand current coverage
  • [ ] Add tests for request distribution fairness using mock services with varying latencies
  • [ ] Add tests for dynamic service discovery integration (tower/src/discover/list.rs) with P2C
  • [ ] Add tests combining P2C balancer with BufferLayer from tower/src/buffer/layer.rs
  • [ ] Verify tests run with 'cargo test -p tower --lib balance::p2c'

Add missing CHANGELOG entries and document recent API changes in tower/CHANGELOG.md and tower-layer/CHANGELOG.md

The file structure shows CHANGELOG.md exists in multiple workspace crates (tower, tower-layer, tower-service, tower-test) but these are typically user-facing documentation. Given the workspace structure and CI workflows (patch.toml, publish.yml, release.yml), maintaining detailed changelogs is critical for release management. A new contributor could review git history and document breaking changes, new features, and deprecations introduced since the last release.

  • [ ] Check git log for recent commits affecting tower/src and tower-layer/src
  • [ ] Review tower/Cargo.toml and tower-layer/Cargo.toml for version bumps
  • [ ] Document any new public API additions (e.g., new Layer implementations or Service utilities)
  • [ ] Add entries for any bug fixes in tower/src/buffer/ or tower/src/balance/
  • [ ] Follow existing CHANGELOG.md format and add date/version header if missing

Create a comprehensive guide documenting the Builder pattern in tower/src/builder/ with concrete examples

The file structure shows tower/src/builder/mod.rs exists as a core component, and guides/building-a-middleware-from-scratch.md demonstrates Tower's commitment to documentation. However, no builder-specific guide exists. This is a high-value addition because the builder pattern is essential for composing middleware, and the current tower/examples/ only show balance.rs. New contributors could add a detailed guide showing: basic service building, stacking layers, and error handling.

  • [ ] Review tower/src/builder/mod.rs to understand the public API and builder methods
  • [ ] Create guides/building-a-service-with-tower-builder.md
  • [ ] Add 3-4 code examples: basic builder usage, adding single middleware layer, stacking multiple layers, error handling in builders
  • [ ] Reference existing guides/building-a-middleware-from-scratch.md for style/format consistency
  • [ ] Add a reference section linking to generated docs at docs.rs

🌿Good first issues

  • Add comprehensive doctests to tower-service/src/lib.rs Service trait methods—currently minimal examples exist for Service::call(), ready(), and poll_ready() contract
  • Implement a 'logging' middleware example in tower/examples/ that wraps any service and logs request/response metadata; pair with tower-test mock to demonstrate testing
  • Fill in missing benchmarks for common middleware stacks in tower/ (e.g., timeout + rate-limit + log); use criterion crate to compare single vs. stacked middleware overhead

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 251296d — ci: Remove test-msrv job (#853) (tottoto)
  • 8358ee7 — Remove Future Sync bound from ServiceBuilder::boxed_clone_sync() (#851) (garypen)
  • 35188ec — ci: Remove unused working-directory config (#852) (tottoto)
  • 46f9b4f — util: Add ServiceExt::retry (#850) (tottoto)
  • c1e28af — util: Add ServiceExt::buffered (#849) (tottoto)
  • 505e7e6 — ci: Update to actions/checkout v6 (#848) (tottoto)
  • 4b0a6b0 — tower v0.5.3 (seanmonstar)
  • 2c8524a — tower v0.5.3 (seanmonstar)
  • 50fa4b6 — ci: upgrade deny check to v2 (#847) (seanmonstar)
  • 73febcd — fix: Check that jitter is not NaN instead of finiteness (#843) (mathew-horner)

🔒Security observations

The Tower codebase demonstrates good security posture as a well-maintained async networking library. The project uses workspace organization, centralized dependency management, and appears to have CI/CD automation (evidenced by .github/workflows). Primary concerns are: (1) potentially outdated dependency versions that should be audited and updated, (2) reliance on 'deny.toml' for supply chain security which is good but should be verified as active, and (3) minor hygiene recommendations around development workflows. No critical vulnerabilities, injection risks, hardcoded secrets, or exposed credentials were identified in the provided file structure. The library itself is not a deployable application, reducing infrastructure-related risks.

  • Low · Dependency Version Pinning — Cargo.toml (workspace dependencies). Several dependencies use loose version constraints (e.g., 'futures = 0.3.22', 'tokio = 1.6.2') that may allow minor/patch updates with potential security implications. While workspace dependencies are centralized, transitive dependencies could introduce vulnerabilities. Fix: Consider using more conservative version constraints or implementing automated dependency scanning via tools like 'cargo audit' and 'cargo-deny' (already configured with deny.toml).
  • Low · Outdated Dependency Versions — Cargo.toml (workspace dependencies). Some dependencies appear potentially outdated (e.g., tokio = '1.6.2' is from 2021, current versions are significantly newer). Older versions may contain known security vulnerabilities that have since been patched. Fix: Regularly update dependencies to their latest stable versions using 'cargo update' and review CHANGELOG entries for security fixes. The CI workflow should include 'cargo audit' checks.
  • Low · Missing Security Headers in Netlify Configuration — netlify.toml. The netlify.toml file exists but no content provided. Netlify deployments should configure security headers (CSP, X-Frame-Options, etc.) if hosting web frontends. Fix: Configure appropriate security headers in netlify.toml such as Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, and Strict-Transport-Security.
  • Informational · No Evidence of Secret Detection — .gitignore. No .gitignore patterns detected for common secret files (.env, .env.local, secrets.json, etc.). While this is a library rather than an application, development workflows may accidentally commit secrets. Fix: Ensure .gitignore includes patterns for common secret file names and consider using pre-commit hooks (e.g., detect-secrets, truffleHog) to prevent secret commits.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · tower-rs/tower — RepoPilot