HTTP status code · Informational (1xx)
103 Early Hints
103 Early Hints is an interim response that sends Link headers before the final response is ready, so the browser can preconnect to origins and preload critical CSS, fonts or scripts while the server is still building the page. It pays off when HTML takes hundreds of milliseconds to generate.
| Class | 1xx, Informational |
|---|---|
| Defined in | RFC 8297 §2 |
| Cacheable by default | No |
| Safe to retry | Not applicable; the final response follows on the same request |
| Relevant headers |
|
What 103 means
RFC 8297 (2017) defines 103 as a way to send header fields that are likely to appear in the final response. They are only hints: the client must not treat them as metadata of the 103 itself, and the server may send more than one 103 before the final status, for example when a CDN adds its own.
Browser support is narrower than the spec. According to Chrome's documentation, Chrome and Edge act on preconnect and preload hints since version 103, Firefox supports preconnect since 120 and preload since 123, and Safari 17 supports preconnect only. Hints are honored only for top-level navigations, prefetch is ignored, and most browsers accept them only over HTTP/2 or HTTP/3.
Early Hints took over the job HTTP/2 Server Push was meant to do. Push sent the bytes whether or not the browser already had them cached; a 103 only names the resources and lets the browser decide, at the cost of one extra round trip.
When to use it
- Pages with slow server think time: server-rendered HTML that waits on a database or API before the first byte.
- Hint only resources every visit needs and whose URLs are stable: the main stylesheet, a web font, preconnect to your CDN or font host.
- Send it only to navigation requests (Sec-Fetch-Mode: navigate) over HTTP/2 or HTTP/3, as Chrome recommends, and repeat the same Link headers in the final response for clients that ignored the 103.
Common causes
If you run the server
- Early Hints are configured but DevTools shows no gain: the connection is HTTP/1.1, the request is not a navigation, or the hint uses rel=prefetch.
- The browser downloads a file twice: the hinted URL (say app.3f9c.css) no longer matches the hashed name in the HTML after a deploy.
- An old HTTP/1.1 client or proxy breaks on the unexpected 1xx; RFC 8297, section 3, warns about exactly this.
How to fix it
If you run the server
- Generate the hint list from the same build manifest that writes the HTML, so hashed names always match.
- Gate the 103 on HTTP/2 or HTTP/3 and on Sec-Fetch-Mode: navigate; in nginx 1.29+ use early_hints $http2$http3.
- Verify with curl -v --http2 https://example.com/: the 103 block with its Link lines should print before the 200.
How to send 103
Next.js route handlers and FastAPI cannot emit a 103. Put a CDN or proxy in front that generates Early Hints from the Link headers of your final responses, as Cloudflare does.
app.get('/', async (req, res) => {
// Node 18.11+: flushes "103 Early Hints" immediately
res.writeEarlyHints({
link: [
'</assets/app.css>; rel=preload; as=style',
'<https://fonts.gstatic.com>; rel=preconnect'
]
});
const html = await renderPage(); // the slow part
res.send(html);
});mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Link", "</assets/app.css>; rel=preload; as=style")
w.Header().Add("Link", "<https://fonts.gstatic.com>; rel=preconnect")
w.WriteHeader(http.StatusEarlyHints) // 103 goes out now (Go 1.19+)
html := renderPage() // the slow part
// The Link headers stay in the map and are repeated on the 200.
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write(html)
})# nginx 1.29.0+: pass the app's 103 to HTTP/2 and HTTP/3 clients only
location / {
early_hints $http2$http3;
proxy_pass http://app;
}Commonly confused with
- 103 vs 200
- Link headers on the 200 work too, but only once the page is ready; the 103 delivers the same hints during the server think time.
- 103 vs 100
- 100 Continue answers the client's Expect header about uploading a body; 103 is unsolicited and is about the response the client will get.
Frequently asked questions
- Which browsers support 103 Early Hints?
- Chrome and Edge 103+ support preconnect and preload. Firefox supports preconnect from 120 and preload from 123. Safari 17 supports preconnect only. All of them apply hints only to page navigations.
- Does 103 Early Hints replace HTTP/2 Server Push?
- In practice, yes. Chrome turned Server Push off by default in 2022 and pointed sites to Early Hints, which lets the browser skip resources it already has in cache instead of receiving them anyway.
- Should the final response repeat the Link headers?
- Yes. Browsers that ignored the 103, and caches that store the final response, only see the headers on the 200. Chrome's guidance is to keep the Link headers on the final response as well.
- Is it safe to send 103 over HTTP/1.1?
- Risky. Some older HTTP/1.1 clients do not expect an informational response they did not ask for and mis-parse the stream. RFC 8297 and the nginx documentation both suggest limiting it to HTTP/2 and HTTP/3.
Last reviewed by Arielton Oberek.