Skip to content

Hyper

Web & HTTPNetworking/HTTPRust

What it is

Hyper is a low-level, correct and fast HTTP implementation for Rust, supporting HTTP/1 and HTTP/2 for both clients and servers.

Hyper handles the HTTP protocol and leaves routing, extraction and middleware to higher layers. Use it directly when you need protocol-level control.

Installation

cargo add hyper --features full

Getting started

The smallest useful thing you can do with it, and what each part means.

A minimal server
async fn handle(req: Request<hyper::body::Incoming>)
    -> Result<Response<Full<Bytes>>, Infallible> {
    Ok(match req.uri().path() {
        "/health" => Response::new(Full::new(Bytes::from("ok"))),
        _ => Response::builder()
            .status(StatusCode::NOT_FOUND)
            .body(Full::new(Bytes::new()))
            .unwrap(),
    })
}

let listener = TcpListener::bind(addr).await?;
loop {
    let (stream, _) = listener.accept().await?;
    tokio::spawn(async move {
        http1::Builder::new()
            .serve_connection(TokioIo::new(stream), service_fn(handle))
            .await
    });
}
This is what Axum builds on. Writing it directly is worthwhile only when you need control over the connection lifecycle — otherwise use a framework.

Advanced usage

Where the library earns its place over a simpler alternative.

Streaming bodies without buffering
use http_body_util::{BodyExt, StreamBody};

// Read an incoming body in frames rather than collecting it all.
let mut body = req.into_body();
while let Some(frame) = body.frame().await {
    if let Some(chunk) = frame?.data_ref() {
        hasher.update(chunk);   // constant memory regardless of size
    }
}

// Stream a response out of an async iterator.
let stream = futures::stream::iter(rows.into_iter().map(|r| {
    Ok::<_, std::io::Error>(Frame::data(Bytes::from(serde_json::to_vec(&r)?)))
}));
Response::new(StreamBody::new(stream))
Collecting a body into memory is how services fall over on large uploads. Frame-by-frame processing keeps memory flat whatever the payload size.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

the trait Body is not implemented
Hyper 1.x moved body helpers into http-body-util. Use Full, Empty or BoxBody from there.
Memory grows with request size
The body is being collected. Process it frame by frame, and enforce a maximum length.

Best practices

  • Use Axum or another framework unless you specifically need protocol-level control.
  • Stream bodies rather than collecting them; an unbounded collect is a denial-of-service vector.
  • Set connection timeouts — Hyper does not impose them for you.
  • Note the 0.14 and 1.x APIs differ substantially; check which version an example targets.

Background

Why it exists, and what it was reacting to.

Hyper is the foundation nearly every Rust HTTP tool sits on — reqwest, Axum, Tonic and Warp all build on it. It deliberately stays low-level so those layers can make their own ergonomic choices.