Most teams do not ship an HTTP cache. They ship Redis with custom key logic baked into the application, or they skip caching entirely and just scale up the backend. Both are the wrong answer.
HTTP caching is a solved problem at the protocol level. Your application should not be reinventing it.
Varnish is the standard tool here. It is powerful. It handles stale-while-revalidate, conditional requests, and cache invalidation correctly. It has been doing this for twenty years.
It is also hard to use. Varnish Configuration Language is its own thing. You need to learn it before you can do anything useful, and misconfiguration is silent. Teams look at the setup cost and decide their backend can handle the load.
This is the gap I built Relay to fill.
Relay is an HTTP caching proxy. You put it in front of your backend, point your traffic at it, and it handles the caching layer. Single binary, TOML configuration, no separate runtime.
The goal was to make infrastructure-level HTTP caching accessible. If you can configure Nginx you can configure Relay.
Stale-while-revalidate and stale-if-error. These are the two most valuable caching behaviors most teams never use. Serve the stale cached response immediately while revalidating in the background. Keep serving the last good response if the origin goes down. Your users do not wait for your database.
Conditional requests. Relay handles If-None-Match and If-Modified-Since correctly. Clients get 304s when content has not changed. Bandwidth drops without any application changes.
Cache invalidation. The hard problem. Relay gives you three tools:
Multiple storage backends. Start with in-memory. Move to disk when you need persistence. Move to Redis when you need a distributed cache across multiple Relay instances. The configuration changes, your application does not.
Smart cache key normalization. Query parameters that do not affect the response get stripped from cache keys automatically. This kills duplicate cache entries without touching the backend.
Rust was the right choice here for the same reasons it is the right choice for any network proxy. Zero-cost abstractions, no garbage collector pausing during high throughput, and memory safety without the runtime overhead.
Point Relay at your backend and configure your cache rules in TOML. For most applications the default settings handle the common cases. For complex invalidation patterns the tag-based system gives you surgical control without writing custom cache logic in the application.
Docker support is included if you are running containers.
The code is open source at github.com/stephenfairchild/relay. The site is at relay-http.com.