---
title: Early Hints
summary: null
url: https://www.fastly.com/documentation/reference/http/early-hints
---

[103 Early Hints](https://developer.mozilla.org/docs/Web/HTTP/Reference/Status/103) is an informational response code that allows the server to send a "pre-response" to the browser while it is still generating the main HTML.

Traditionally, when a user visits a website, a frustrating game of back-and-forth happens behind the scenes:

1. **The Request:** The browser asks the server for index.html.

2. **The Server "Think" Time:** The server receives the request, but it can't send the HTML immediately. It has to talk to databases, call APIs, and assemble the page. This often takes anywhere from 100ms to over a second.

3. **The Idle Browser:** During this time that the server is "thinking", the browser's network connection sits completely idle.

4. **The Discovery Delay:** Only after the server finishes and sends the HTML can the browser look inside it, discover the critical CSS and JavaScript files, and then start downloading them.

This creates a massive bottleneck where the user is staring at a blank screen while assets wait in a queue.

Your edge code can make use of **103 Early Hints** to send instructions to the browser during this "idle browser" period. In effect, your code tells the browser that, while the server is still working on the HTML, the browser is going to need certain resources such as CSS, JS, and other files. The browser can then go ahead and start downloading them in the meantime.

### How it works

In a standard HTTP setup, a server can only send one response header per request. However, the HTTP specification allows servers to send interim (temporary) responses before the final one, as long as they use a 1xx status code. Early Hints leverages this capability to send two sets of headers: an interim 103 response, followed by the final 200 response.

If you were to look at the literal bytes traveling over the network cable during that single request, it looks like this:

> **IMPORTANT:** Fastly only supports `103 Early Hints` over HTTP/2 or HTTP/3. While the examples below are shown in a text-based format for readability, HTTP/2 and HTTP/3 are binary protocols that transmit these messages as separate binary `HEADERS` frames.

1. The Client Request

   The browser opens a connection and asks for the page.

   ```http
   GET /homepage HTTP/2
   Host: example.com
   ​
   ```

2. The Interim Response (The "Early Hint")

   The server immediately sends back the 103 headers. Crucially, _the server does not close the connection_ and does not send a body yet.

   ```http
   HTTP/2 103 Early Hints
   Link: </css/style.css>; rel=preload; as=style
   Link: </js/app.js>; rel=preload; as=script
   ​
   ```

   Note the blank line at the end of the response here. Normally, this means "end of headers," and because it's a `1xx` code, the browser knows to keep listening for the next status code.

3. The Final Response

   While the browser is off downloading `main.css` and `app.js`, the server finishes thinking and sends the final, official response down the exact same pipe:

   ```http
   HTTP/2 200 OK
   Content-Type: text/html
   Content-Length: 4096
   ​
   <!DOCTYPE html>
   <html>
   <head>...</head>
   <body>...</body>
   </html>
   ```

   Only now, after the 200 OK header and body are fully delivered, is the specific request-response transaction considered finished.

### Implementing Early Hints in edge code

Fastly's platform has support for sending Early Hints in edge code. It is only effective for clients connecting using HTTP/2 or later.

### Vcl

In a VCL service, call the `early_hints` function.

```vcl
sub vcl_recv {
  if (fastly_info.is_h2 || fastly_info.is_h3) {
    early_hints("Link: </css/style.css>; rel=preload; as=style", "Link: </main/app.js>; rel=preload; as=script");
  }
}
```

### Rust

In a Compute application written in Rust, use the [`send_to_client()`](https://docs.rs/fastly/latest/fastly/struct.Response.html#method.send_to_client) method of a `Response` instance with a `103` error code. Any number of `103 Early Hints` responses may be sent before sending the final response. Any response with status code other than `103` will be treated as the final response.

```rust
use fastly::{Error, Request, Response};
#[fastly::main]
fn main(req: Request) -> Result {

    let early_hint = Response::from_status(103)
        .with_header("Link", "</css/style.css>; rel=preload; as=style")
        .with_header("Link", "</main/app.js>; rel=preload; as=script");

    early_hint.send_to_client();

    Ok(req.send("example_backend")?)
}
```

### Javascript

In a Compute application written in JavaScript, use the [`sendEarlyHints()`](https://js-compute-reference-docs.edgecompute.app/docs/globals/FetchEvent/prototype/sendEarlyHints) method of the `FetchEvent` object, passing in any initializer suitable for headers. This can be a simple object literal with `string` values; an array of name-value pairs, where each pair is a 2-element `string` array; or an existing `Headers` object.

Any number of `103 Early Hints` responses may be sent before sending the final response.

```js
/// <reference types="@fastly/js-compute" />

addEventListener("fetch", event => event.respondWith(handler(event)));

function handler(event) {
    event.sendEarlyHints([
        ['Link', '</css/style.css>; rel=preload; as=style'],
        ['Link', '</main/app.js>; rel=preload; as=script'],
    ]);

    return fetch(event.request, { backend: "example_backend" });
}
```

### Go

In a Compute service written in Go, use the [`WriteHeader()`](https://pkg.go.dev/github.com/fastly/compute-sdk-go/fsthttp#ResponseWriter.WriteHeader) function of the `ResponseWriter` interface, passing in a `103` status code. This will write all headers collected in the `ResponseWriter` to the response. It's important to call `Reset()` on the headers afterwards to clear out the entries sent as early hints.

```go
func main() {
	fsthttp.ServeFunc(func(ctx context.Context, w fsthttp.ResponseWriter, r *fsthttp.Request) {
        w.Header().Add("Link", "</css/style.css>; rel=preload; as=style")
        w.Header().Add("Link", "</main/app.js>; rel=preload; as=script")
        w.WriteHeader(http.StatusEarlyHints)

        resp, err := r.Send(ctx, "example_backend")
        if err != nil {
            fsthttp.Error(w, err.Error(), fsthttp.StatusBadGateway)
            return
        }

        w.Header().Reset(resp.Header)
        w.WriteHeader(resp.StatusCode)
        io.Copy(w, resp.Body)
	})
}
```

### Cpp

In a Compute application written in C++, use the [`send_to_client()`](https://cpp-compute-sdk.fastly.dev/classfastly_1_1http_1_1Response.html#a74bf3303db3ff132f5e1912f05e80d64) method of a `Response` instance with a `103` error code. Any number of `103 Early Hints` responses may be sent before sending the final response. Any response with status code other than `103` will be treated as the final response.

```cpp
int main() {
    auto early_hints_resp = fastly::Response::from_status(103)
        .with_header("Link", "</css/style.css>; rel=preload; as=style").value()
        .with_header("Link", "</main/app.js>; rel=preload; as=script").value();
    early_hints_resp.send_to_client();

    auto res = fastly::Request::from_client().send("example_backend").value();
    res.send_to_client();
}
```


