HTTP/2 Server Push Explained
Tags: performance, http2, serverpush, webdev
Published: 2020-02-12 21:07:51

---
title: HTTP/2 Server Push Explained
published: true
description: Learn how to improve site performance by enabling HTTP/2 server push
tags: performance, http2, server push, webdev
---

HTTP/2 Server Push is a new feature released along with HTTP/2 that allows compatible servers to push resources to the client before the client requests the resources. Instead of having to wait for the client to download the document, parse it, and send more requests to the server, the server just sends the documents it knows the client will need.

> HTTP/2 allows a server to pre-emptively send (or "push") responses (along with corresponding "promised" requests) to a client in association with a previous client-initiated request. *[RFC 7540](https://tools.ietf.org/html/rfc7540#section-8.2)*

This allows sites to load much faster since it saves one round-trip between the client and the server. This optimization is basically free in terms of development work because everything is implemented at the protocol level.

# What is Server Push?

Traditionally, HTTP clients like browsers connect to a server, request a page, receive the page, parse the page, then request any additional resources that the page requires. Any resources required to load the page require a separate request after loading the page even though they're sent any time the page is requested.

Server Push improves this process by "pushing" resources to the browser before the browser even asks.

![Server push explanation](https://dev-to-uploads.s3.amazonaws.com/i/k24or5sxlexkuwxvowwc.png)

For example, instead of requesting the document, receiving the document, then requesting the resources, the client just has to request the document and receives the document and resources in the response.

In the example above, HTTP/2 Server Push increases page load time by 60 ms. This may not seem like much but Server Push improves load time by 25% by just enabling a simple configuration option.

## How does it work?

This section will explain the technical details behind server push. If you don't care about that, just skip to the next section.

### HTTP/2 streams

Unlike HTTP/1, HTTP/2 is a binary protocol. Where HTTP/1 sends the normal `GET /` request in plain text, HTTP/2 uses binary encoding to save bytes. For example, HTTP/2 sends a `HEADERS` frame encoded in binary similar to the `PUSH_PROMISE` frame above and then it sends a `DATA` frame to send site data to the client.

HTTP/2 also comes with a new feature called *streams*. Streams allow multiple streams of frames to be sent over a single connection. This allows multiple requests/responses to be sent and received over a single connection. Whereas HTTP/1 supports only a single request/response at a time, HTTP/2 allows many requests/responses as long as there is enough bandwidth to send them.

This is a key feature for server push because server push involves sending multiple different resources at the same time.

### HTTP/2 Server Push

First of all, the server and client must agree to support the feature. The client may disable server push by setting the `SETTINGS_ENABLE_PUSH` setting to 0 included in the HTTP/2 settings frame. If the client does this, the server should not push any resources to the client through Server Push.

After the client sends an HTTP/2 request to the server with `SETTINGS_ENABLE_PUSH` set to 1, the server will first send back a `PUSH_PROMISE` frame indicating to the client that it will be pushing some resources to the client. This includes a 31-bit stream ID and headers for the requested resource to provide context.

```
+---------------+
|Pad Length? (8)|
+-+-------------+-----------------------------------------------+
|R|                  Promised Stream ID (31)                    |
+-+-----------------------------+-------------------------------+
|                   Header Block Fragment (*)                 ...
+---------------------------------------------------------------+
|                           Padding (*)                       ...
+---------------------------------------------------------------+
```

The server sends these even before the page response so that the client doesn't request any of the resources the server plans to push.

After sending the initial `PUSH_PROMISE` frame, the server then begins sending push responses on the streams identified by the stream ID sent previously in the `PUSH_PROMISE` frames. The client doesn't send any requests for resources that it knows the server is pushing.

Clearly, HTTP/2 server push requires support by the server and the client, but the client can always fall back to HTTP/1. Next, I'll discuss HTTP/2 Server Push support.

## What browsers support Server Push?

![Server push supported browsers](https://dev-to-uploads.s3.amazonaws.com/i/korqgi2k7up3th1kqbj4.png)

HTTP/2 Server Push is supported on all major browsers (except for IE on Windows 7).
- Firefox has supported HTTP/2 server push since February 2015.
- Chrome has supported HTTP/2 server push since March 2015.
- Safari as supported HTTP/2 server push since June 2015.

Clearly, HTTP/2 Server Push is very widely supported. It works on 95.5% of all users' devices.

# How much does it improve load times?

I ran a test on 500 of the top websites according to [moz.com](https://moz.com/top500) and I calculated the time spent loading the longest-loading resource from the server. This isn't a perfect test since there are other factors that can marginally lower the benefit, but this should be a good estimate.

![Server push speedup](https://dev-to-uploads.s3.amazonaws.com/i/f34c40gxnt7hmama2agt.png)

In some cases, over 1 second could be saved simply by enabling a configuration option in the web server. Generally, over 200 ms can be saved by enabling HTTP/2 server push.

Especially in cases where request chains are long, server push can be a huge help. For example, if you have HTML that loads CSS that loads a font, server push can decrease the latency of loading the CSS and font to 0.

You can use a tool like [pagecheck](https://pagecheck.app) to check request chains within your site.

# How do I implement it?

HTTP/2 Server Push is implemented by most major web servers. Generally, you can add a reverse proxy in front of your site in order to still use your existing web framework, but also include some important features like Server Push or caching.

## Apache

Apache supports HTTP/2 server push through a module called `mod_http2`. In order to enable this module, add this to your `httpd.conf`:

```conf
LoadModule http2_module modules/mod_http2.so
```

Then, you can enable HTTP/2 as a supported protocol from Apache by adding this line:

```conf
Protocols h2 h2c http/1.1
```

Make sure that `SSLCipherSuite` is configured with an HTTP/2 compatible cipher. You can also just leave it as a default value and it will be configured properly as long as you have an up-to-date version of OpenSSL. Don't use any ciphers from [this list](https://httpwg.org/specs/rfc7540.html#BadCipherSuites) as they are not supported by HTTP/2.

With Apache, you can push responses in one of two ways:

1. Add `Link` headers to your application so the application notifies Apache of which resources need to be pushed. `Link` headers look like this:

```
Link </xxx.css>;rel=preload, </xxx.js>; rel=preload
```

2. Add `Link` headers manually in your Apache server config:

```
<Location /xxx.html>
  Header add Link "</xxx.css>;rel=preload"
  Header add Link "</xxx.js>;rel=preload"
</Location>
```

All of the information from this section comes from the [apache docs](https://httpd.apache.org/docs/2.4/howto/http2.html#push)

## NGINX

NGINX supports HTTP/2 server push similarly to Apache.

First, enable HTTP/2 support on your server by adding `http2` to the `listen` directive:

```
listen 443 ssl http2;
```

Then, again you can either add `http2_push` directives to your application similar to above:

```conf
location = /demo.html {
  http2_push /style.css;
  http2_push /image1.jpg;
  http2_push /image2.jpg;
}
```

Or, you can add a `http_push_preload on` directive to your server configuration which will respect headers sent from the application:

```conf
location = /app {
  proxy_pass http://upstream;
  http2_push_preload on;
}
```

All of this information and more can be found on [NGINX's blog post for server push](https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/).

# Conclusion

HTTP/2 Server Push allows developers to decrease load times for free. Literally just enable a configuration option and set your application up to send `Link` headers and your application will load 25-50% faster.

HTTP/2 Server Push is supported by 95% of users' browsers, so it should be a no-brainer for any site.

Shameless plug: [pagecheck](https://pagecheck.app) allows you to track your load times across websites including front-end statistics which HTTP/2 would affect. If you're interested or you have a use case we haven't thought of yet, you can also send me an email [here](mailto:julian@pagecheck.app).