Disclaimer: I hate writing. I’m using AI to get my ideas onto paper. The opinions, experience, and numbers are mine. The grammar is not.
I am building LODE because HTTP/3 in Rust feels like it stopped one layer too early.
Not because Rust cannot speak HTTP/3. It can.
Not because reqwest is bad. reqwest is fantastic. I use it constantly. This is not a dunk on one of the best libraries in the Rust ecosystem.
The problem is narrower, which is exactly why it bothers me so much: the protocol support exists, but the client policy I want does not.
The missing piece is not HTTP/3 support. The missing piece is transport policy.
This Is Not a reqwest Dunk
I want to be fair about the current state because it is easy to make this sound dumber than it is.
reqwest supports HTTP/1.1 and HTTP/2 in the normal path. It also has experimental HTTP/3 support behind the http3 feature. That matters. It is real work, and I do not want to undersell it.
But the HTTP/3 path is explicit prior knowledge. You build a client that uses HTTP/3, and you ask for HTTP/3. If that QUIC path does not work on the client’s current network, the request fails.
That is a valid API.
It is not the API I want for mobile clients.
What I want is not “force HTTP/3.” What I want is closer to:
try HTTP/3 when it is likely to work
if it works, use it
if it does not, fall back to HTTP/2 or HTTP/1.1
remember what failed
try again later when the network changes
That should be boring. It is how the application layer wants the world to look. The request should succeed if there is a usable transport. HTTP/3 should be a performance opportunity, not a reliability bet.
The Wrong Failure Mode
The failure mode I hate is simple.
Your server supports HTTP/3. Your client supports HTTP/3. Everything looks good in your test environment. Then the user walks onto a network that does not pass UDP correctly.
Now what?
If the answer is “the request fails,” then enabling HTTP/3 made the application less reliable.
That is backwards.
HTTP/3 should not be a new way to fail a request that could have succeeded over HTTP/2. QUIC availability should not become part of the application correctness model. Most application code does not care which HTTP version moved the bytes. It cares whether the response came back.
There are obviously cases where the application should care. Debugging, protocol testing, controlled environments, explicit prior knowledge, benchmarking, interop work. All valid.
But that should not be the default shape for a mobile-facing client.
Mobile Makes This Obvious
Servers are easy compared to clients.
If you own the server, you can enable HTTP/3. You can tune it. You can monitor it. You can stare at the dashboard until it turns green.
The client does not live in your dashboard.
The client lives on hotel Wi-Fi, carrier NAT, captive portals, airplane Wi-Fi, tunnels, VPNs, office firewalls, school networks, and whatever cursed middlebox someone bought ten years ago and has been too afraid to reboot.
A server can support QUIC perfectly and the client can still be sitting on a network path where UDP is broken, throttled, blocked, or just weird.
That is the part that makes the current shape frustrating. QUIC is exactly the kind of transport you want available on bad last-mile networks. Uber wrote about this years ago. The gains are not imaginary. Outside the extremely comfortable network conditions a lot of us get used to in North America, UDP can be the better answer more often than people assume.
But only if using it does not make reliability worse.
If enabling HTTP/3 means some percentage of users now fail harder, the rational application developer turns it off. That is not because they hate new protocols. It is because users do not grade you on protocol ambition. They grade you on whether the app works while they are standing in a train station with two bars.
The Missing Layer
LODE is an attempt to build the layer I keep wanting.
The name is a small joke. It is a nod to lodestone, the thing that pulls you in the right direction. Also, “loaded” was boring.
The thing I want LODE to decide is not complicated to describe, but it is annoyingly mechanical to implement correctly:
Does this origin probably support HTTP/3?
Does this network currently seem hostile to QUIC?
Has QUIC failed here recently?
Is this request safe to replay?
Did the failure happen before the request was committed?
Should the next attempt use H2 or H1?
When should H3 be tried again?
None of those questions are exotic. They are just not the same question as “can this library speak HTTP/3?”
That distinction is the whole project.
Rust has the pieces. hyper, h2, h3, quinn, rustls, reqwest, and the surrounding ecosystem are all real. The missing thing is the coordinator that treats H1, H2, and H3 as a set of transport options instead of separate decisions the application has to make up front.
The policy layer is the product.
Cronet Proves the Shape
This is not a novel idea.
Cronet already proves the shape. It is the Chromium networking stack packaged for applications, and it does a lot of what I want: modern transport negotiation, fallback, connection racing, network-change awareness, and a long tail of behavior learned from the real internet being terrible.
There is a reason serious mobile apps use it.
There is also a reason I do not want to reach for it by default in a Rust project.
Cronet is powerful, but it brings Chromium-shaped gravity with it. C++. Size. Platform integration. Build complexity. Crash surface. The feeling that you invited a city into your house because you needed a sink.
Sometimes that is the right trade. Big companies make that trade because the networking stack is worth it.
LODE is me asking whether the Rust ecosystem can have a smaller answer for the part I care about most: opportunistic modern transports with graceful fallback.
Not Chromium networking.
Not a browser.
Just the boring policy that lets an application benefit from HTTP/3 without betting the request on it.
Fallback Is Not Magic
The easy way to lie about this project would be to say “automatic fallback” and pretend every request can be retried safely.
It cannot.
Fallback is only correct when replay is correct. If you are streaming a one-shot upload and the server may have already observed part of the body, blindly trying again over another transport is how you get duplicate writes, corrupted uploads, and an incident review where everyone suddenly cares about idempotency.
So the first version of LODE is intentionally conservative.
Buffered requests first.
If the request body can be replayed safely, LODE can make transport attempts, fail before commitment, and try the next viable path. If the body cannot be replayed, the API needs to make that visible instead of pretending the network layer has a time machine.
That constraint is not a weakness. It is the contract.
I would rather ship a narrow thing that is honest than a broad thing that corrupts someone’s mental model of what happened on the wire.
What I Want the API To Feel Like
The dream is boring code:
let client = lode::Client::new();
let response = client
.get("https://api.example.com/data")
.send()
.await?;
Maybe that used HTTP/3.
Maybe it tried HTTP/3, decided this network was cursed, and used HTTP/2.
Maybe this origin has not advertised HTTP/3 yet, so it stayed on the normal TCP path.
Maybe QUIC failed five seconds ago and LODE is giving it a short timeout before trying again.
The application should not have to care unless it asks to care.
That is the shape I want: a Rust HTTP client layer that treats transport selection as policy, not ceremony.
The Actual Point
There is a pattern I keep noticing in infrastructure and systems work: the hard part moves up a layer.
At first, the hard part is making the protocol work at all. Then enough people do that work, and the hard part becomes choosing when to use it. Then enough people solve that inside giant private stacks, and the hard part becomes making that behavior available without dragging the giant stack with it.
That is where HTTP/3 in Rust feels to me right now.
The protocol work exists. The ecosystem has pieces. The missing thing is the small, boring, stubborn policy layer that assumes the network is hostile and the application still needs an answer.
LODE is that experiment.
HTTP/3 should be something your application benefits from when the network allows it, not something that makes your application brittle when the network is weird.
That is the project.