A browser can discover a site's HTTP/3 support two ways: either by first connecting
over HTTP/1 or HTTP/2 and reading its Alt-Svc HTTP header, or right
away from an HTTPS DNS record lookup. Only with the HTTPS DNS record
can the browser use HTTP/3 on the first connection, saving a round trip using QUIC.
Alt-Svc HTTP
header, not in DNS, though it could have published both. A published
HTTPS record would have saved each one a round trip on the first
connection.
This site eats its own dog food: savearoundtrip.com publishes an HTTPS record with h3, IP hints, and ECH.
Queries Cloudflare's DNS-over-HTTPS endpoint for the HTTPS
(type 65) record, live, from your browser, and decodes the SVCB wire
format. Nothing is sent to a server of ours; there isn't one.
Can't I just check Alt-Svc too? Not from a web page. CORS
forbids reading another origin's response headers in the browser. Spotting
the Alt-Svc-but-no-record case across the web has to happen
off the browser; that is where the real-browser data
below comes from.
A round trip is the time for one message to reach the server and come back, bounded by the speed of light: very roughly 5 to 20 ms within a city, 40 to 80 ms across a country, and 150 ms or more across an ocean or over a mobile network. Real latency depends on where you and the server are; see Cloudflare Radar for more data.
You pay it once per origin, on the first connection only; later requests reuse that connection. A page often pulls from several origins (a subdomain, a CDN, some third parties), so it can be paid several times in one load. Browsers do coalesce origins that resolve to the same server and share a certificate onto a single connection, which avoids the extra cost; origins that do not coalesce each pay their own.
And it is paid where people notice. Under about 100 ms an interaction feels instant; past that it starts to feel like waiting (Google's RAIL model). On the first connection, a single round trip can eat that whole budget.
Alt-Svc (RFC 7838)
is an HTTP response header. To read it, the client must finish a request, which
means it has already opened a TCP connection, done a TLS handshake,
and spoken HTTP/1.1 or HTTP/2. Only then does it learn "by the way, I also
speak HTTP/3". The HTTP/3 upgrade lands on the next connection.
sequenceDiagram
participant C as Client
participant D as DNS
participant S as Your server
Note over C,S: First connection
C->>D: look up A / AAAA
D-->>C: IP address
C->>S: TCP + TLS handshake
S-->>C: connected (HTTP/2)
C->>S: HTTP/2 request
S-->>C: response + Alt-Svc: h3
Note over C,S: only now does the client learn you speak HTTP/3
Note over C,S: Second connection
C->>S: QUIC + HTTP/3 handshake
S-->>C: connected (HTTP/3)
An HTTPS record (RFC 9460) carries the same "I speak HTTP/3" signal, but in the DNS. The client reads it during the name resolution it was going to do anyway, before it opens any connection. So it can make its very first connection over QUIC/HTTP/3, with no earlier HTTP/1 or HTTP/2 connection spent just to find out.
sequenceDiagram
participant C as Client
participant D as DNS
participant S as Your server
Note over C,S: First connection
C->>D: look up HTTPS record
D-->>C: alpn=h3 + IP hints (+ ECH)
C->>S: QUIC + HTTP/3 handshake
S-->>C: connected (HTTP/3)
C->>S: HTTP/3 request
S-->>C: response
The HTTPS resource record (RFC 9460, Nov 2023) folds everything a client needs to open the optimal connection into the DNS answer it was already fetching. Concretely:
The alpn SvcParam lists the
ALPN protocol IDs the
endpoint speaks, e.g. h3 (HTTP/3) and
h2. Because it arrives during name resolution, the client
can pick QUIC for its very first connection instead of discovering
h3 only after a previous HTTP/1 or HTTP/2 connection.
The ech SvcParam carries the endpoint's ECHConfigList
public keys (RFC 9849).
ECH encrypts the TLS ClientHello, including the SNI server name, so a
network observer can't see which site you're visiting. This is a
chicken-and-egg problem an HTTP header can't solve: you need the public
key before you send the first ClientHello, which is exactly when no
connection exists yet. Only an out-of-band channel, the DNS (the
HTTPS record), can bootstrap ECH. No HTTPS RR, no ECH.
ipv4hint and ipv6hint ship candidate addresses
inside the HTTPS answer, so the client can begin connecting and running
Happy
Eyeballs v3 right away, using them as provisional answers while the A
and AAAA lookups run in parallel. The client still issues those queries,
and the real records supersede the hints once they arrive; the hints just
save it from waiting on them to make the first attempt.
Alt-Svc has no equivalent.
Reachability lives in the DNS with a normal TTL, instead of being smeared
across per-origin HTTP-header caches with their max-age
dilemma: too long and clients use stale alternatives, too short and they
fall back to older protocols more often than they should. The browser was
going to do a DNS lookup anyway; this just makes that lookup carry the answer.
| capability | Alt-Svc HTTP header (RFC 7838) | HTTPS RR (RFC 9460) |
|---|---|---|
| learned when? | after a full connection | during DNS resolution |
| h3 on first connection | no | yes |
| IP hints | n/a | ipv4hint / ipv6hint |
| ECH keys | impossible | ech param |
| source of truth | HTTP header + fragile cache | the DNS, with a TTL |
Firefox Nightly Measured by Firefox itself, via Mozilla's public GLAM telemetry.
A browser can learn that a server speaks HTTP/3 in two ways: from
the Alt-Svc HTTP response header (seen only after it has
already connected), or from an HTTPS DNS record (seen before
connecting). So every connection falls into one of four groups:
Share of measured connections, Firefox Nightly. The four groups cover every connection, so they add up to 100%. The two right-hand groups had a usable HTTPS record; Alt-Svc only is the gap a record would close.
Each bar is one Nightly build, split into the four groups (100%). Firefox Nightly only.
A ServiceMode HTTPS record advertising h3, with address hints:
; zone file (BIND-style)
example.com. 3600 IN HTTPS 1 . alpn="h3,h2" ipv4hint=203.0.113.10 ipv6hint=2001:db8::10
Reading it left to right:
example.com. the name you publish it under; the trailing dot makes it fully qualified.3600 the TTL: how many seconds a resolver may cache the record.IN the DNS class (Internet), as on every web record.HTTPS the record type (RFC 9460).1 the priority. 1 or higher is ServiceMode (this record carries the parameters); 0 is AliasMode, which just points at another target.. the target host. . means the owner name itself, here example.com.alpn="h3,h2" the protocols the server speaks, best first: h3 is HTTP/3, h2 is HTTP/2.ipv4hint / ipv6hint addresses the client can start connecting to right away, alongside its A/AAAA lookups.Most managed DNS providers (Cloudflare, Route 53, and others) expose an HTTPS record type directly. Verify yours with the checker.
Firefox Nightly Of the connections where Firefox saw an HTTPS record, the share whose record carried each feature.
Source: Firefox Nightly, via GLAM.
Some do. Cloudflare, for one, serves an HTTPS record with
alpn="h3" automatically for proxied zones. Others leave it to
you. The quickest way to find out is to check your domain
above.
No. A client that doesn't understand HTTPS records just ignores them and
falls back to ordinary A/AAAA lookups (and your Alt-Svc header,
if you still send it). Publishing one is strictly additive.
Even better: once a client has spoken HTTP/3 with you, a return visit can resume the QUIC connection in 0-RTT, putting the first request on the wire with no handshake round trip at all. And the HTTPS record itself is cached for its TTL like any DNS answer, so repeat visits usually skip the lookup too.
Alt-Svc header?Not yet. Keep sending it as a fallback for clients that did not get the HTTPS record. With the record in place, most clients learn about HTTP/3 from DNS instead, and no longer spend a round trip discovering it.