aioduct
Async-native Rust HTTP client built directly on hyper 1.x — no hyper-util, no legacy APIs.
Documentation | API Reference | Crates.io
Why aioduct?
- reqwest depends on hyper-util's
legacy::Client, wrapping hyper 0.x-style patterns over hyper 1.x with years of backwards-compatibility baggage. - hyper-util labels its own client as "legacy" — the hyper team acknowledges it's not the long-term answer.
- hyper 1.x provides clean connection-level primitives, but no production client uses them directly.
aioduct uses hyper 1.x the way it was intended — as a protocol engine you drive yourself, with your own connection pool, TLS, and runtime integration.
Features
- No hyper-util — custom IO adapters and executor directly against
hyper::rttraits - Multi-runtime — tokio, smol, and compio (io_uring) via feature flags; WASM/browser support
- rustls TLS — async handshake with ALPN-based HTTP/1.1 and HTTP/2 negotiation
- Connection pooling — keyed by (scheme, authority) with idle timeout and per-host limits
- Redirect following — RFC-compliant handling of 301/302/303/307/308 with sensitive header stripping and content header removal
- Cookie jar — automatic cookie storage, domain/path/subdomain matching, Max-Age and Expires expiration, Secure flag enforcement, SameSite (Strict/Lax/None), cookie prefixes (__Host-, __Secure-)
- Timeouts — per-request, client-level, connect, and read timeouts
- Retry — configurable exponential backoff with retry budgets, Retry-After header support, 429 Too Many Requests retry
- Decompression — automatic gzip, brotli, zstd, deflate response decompression
- Proxy — HTTP CONNECT tunneling, SOCKS4/SOCKS4a, SOCKS5, system proxy detection (HTTP_PROXY/HTTPS_PROXY/NO_PROXY)
- Middleware — pluggable request/response interceptors via trait or closure
- Rate limiting — token-bucket rate limiter for outgoing requests
- Caching — in-memory HTTP cache with immutable responses, stale-while-revalidate, stale-if-error (fallback on 5xx/connection failure)
- HSTS — automatic HTTP-to-HTTPS upgrade for Strict-Transport-Security domains
- SSE — Server-Sent Events stream parsing for LLM APIs
- Multipart —
multipart/form-datauploads with text fields and file parts - Streaming — chunked downloads and streaming uploads without buffering
- Chunk download — parallel HTTP Range requests for large files
- HTTP upgrade — WebSocket and other protocol upgrades via HTTP/1.1 101
- Blocking client — synchronous wrapper for non-async contexts (requires tokio)
- Custom DNS — pluggable resolver via the
Resolvetrait; hickory-dns integration - HTTP/2 tuning — configurable window sizes, frame size, adaptive window, keepalive PINGs
- TCP keepalive — configurable keepalive interval for long-lived connections
- TCP Fast Open — reduced connection latency on Linux via TCP_FASTOPEN_CONNECT
- Local address binding — bind outgoing connections to a specific local IP
- JSON — optional
jsonfeature for request/response serialization - Problem Details — RFC 9457
application/problem+jsonresponse parsing (requiresjsonfeature) - Happy Eyeballs — RFC 6555 connection racing, interleaves IPv6/IPv4 with 250ms stagger
- Digest auth — automatic HTTP Digest authentication with 401 retry (RFC 7616, MD5)
- Bandwidth limiter — token-bucket byte-rate throttle for download speed limiting
- Netrc —
.netrcfile parser and middleware for automatic credential injection - Auth helpers — bearer token, basic auth
- Form data — URL-encoded form bodies
- Query parameters — with percent-encoding
- Default headers — automatic User-Agent, configurable defaults
- Observability — optional tracing spans and OpenTelemetry middleware
- Tower integration — use aioduct as a tower
Service - Link headers — RFC 8288 Link header parsing for pagination and discovery
- Forwarded header — RFC 7239 Forwarded header builder and parser
Quick Start
[]
= { = "0.1", = ["tokio"] }
use ;
use TokioRuntime;
async
HTTPS
Enable the rustls feature:
= { = "0.1", = ["tokio", "rustls"] }
let client = with_rustls;
let resp = client.get?.send.await?;
Feature Flags
| Feature | Description | Stability |
|---|---|---|
tokio |
Tokio async runtime | Stable |
smol |
Smol async runtime | Stable |
compio |
Compio runtime (io_uring / IOCP) | Experimental |
wasm |
Browser/WASM runtime via web-sys | Experimental |
rustls |
TLS via rustls (required for HTTPS) | Stable |
rustls-native-roots |
Use OS certificate store instead of webpki-roots | Stable |
json |
JSON request/response with serde | Stable |
charset |
Charset decoding via encoding_rs | Stable |
gzip |
Gzip response decompression | Stable |
deflate |
Deflate response decompression | Stable |
brotli |
Brotli response decompression | Stable |
zstd |
Zstd response decompression | Stable |
blocking |
Synchronous blocking client (requires tokio) | Stable |
hickory-dns |
DNS via hickory-resolver (requires tokio) | Stable |
tower |
Tower Service and Layer integration |
Stable |
tracing |
Tracing spans for requests | Stable |
otel |
OpenTelemetry middleware | Stable |
http3 |
HTTP/3 via h3 + h3-quinn | Experimental |
At least one runtime feature must be enabled or compilation will fail.
Examples
JSON
// Requires features = ["tokio", "json"]
let resp = client.post?
.json?
.send
.await?;
let user: User = resp.json.await?;
Form Data
let resp = client.post?
.form
.send
.await?;
Authentication
// Bearer token
let resp = client.get?
.bearer_auth
.send
.await?;
// Basic auth
let resp = client.get?
.basic_auth
.send
.await?;
Query Parameters
let resp = client.get?
.query
.send
.await?;
// GET /search?q=hello%20world&page=1
Client Configuration
use Duration;
let client = builder
.timeout
.max_redirects
.pool_idle_timeout
.pool_max_idle_per_host
.tcp_keepalive
.local_address
.build;
SOCKS5 Proxy
use ProxyConfig;
let client = builder
.proxy
.build;
// With authentication
let client = builder
.proxy
.build;
HTTP/2 Tuning
use Http2Config;
let client = builder
.tls
.http2
.build;
Smol Runtime
use Client;
use SmolRuntime;
block_on;
CLI Tools
The workspace includes two CLI tools built on aioduct:
aioduct-aria
An aria2-inspired parallel download tool. Splits large files into segments and downloads them concurrently using HTTP Range requests.
# Download with 8 segments
# Resume an interrupted download
aioduct-curl
A curl-inspired HTTP tool with familiar flags.
# GET request
# POST with JSON body
# Follow redirects, basic auth, save to file
Both tools are workspace members (publish = false) and serve as real-world integration examples.
Architecture
Client<R: Runtime>
├── RequestBuilder ← fluent API (headers, body, auth, query, timeout)
├── ConnectionPool<R> ← keyed by (scheme, authority), idle eviction
├── TLS (rustls) ← async handshake, ALPN → h1/h2
└── Runtime trait ← TcpStream, Sleep, spawn, resolve
├── TokioRuntime
├── SmolRuntime
└── CompioRuntime
The Runtime trait abstracts over async runtimes:
Comparison
| reqwest | aioduct | |
|---|---|---|
| hyper | 1.x via hyper-util legacy | 1.x direct |
| hyper-util | Required | Not used |
| Runtime | tokio only | tokio / smol / compio / wasm |
| TLS | rustls or native-tls | rustls |
| HTTP/3 | Experimental | Experimental |
| io_uring | No | Via compio |
| Connection pool | hyper-util legacy | Custom h1/h2/h3 |
| Cookie jar | Yes | Yes |
| SSE streaming | No (manual) | Built-in |
| Rate limiting | No | Built-in |
| HTTP caching | No | Built-in |
| HSTS | No | Built-in |
| Link headers | No | Built-in |
| Problem Details | No | Built-in |
| Middleware | Via tower | Built-in + tower |
| Happy Eyeballs | No | RFC 6555 |
| Digest auth | No | Built-in |
| Bandwidth limiter | No | Built-in |
| Netrc | No | Built-in |
MSRV
The minimum supported Rust version is 1.88.0 (edition 2024).
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.