HTTP/2 server push help (for Netlify)

So, I’m trying to use Netlify’s HTTP/2 server push pretty aggressively using a Hugo-generated _headers file. As a basis I used this tutorial and things have been working great thus far.

But there’s one thing I’d like to do to improve the setup: server push images whenever possible. The tricky part about this is determining which images are being loaded on each page. This is easy enough if images are hard-coded parts of page templates and I can hard-core the _headers file but much more difficult when content is Markdown content. Have any of you successfully dealt with this issue before?

In other words, I’d like to be able to replace the ??? here:

{{ range .Site.RegularPages }}
{{ $images := ??? }}
{{ .URL }}
  {{ range $images }}
  Link: <{{ . }}>; rel=preload; as=image
  {{ end }}
{{ end }}

You did read the smashing article about limitations of push didn’t you? Not over-pushing and considering cache issues?

I’m not an expert at all, more wondering if you’ve tested performance?

Yes, I have seen the article. What I’m interested in right now is precisely getting my Netlify setup in a good position to do meaningful performance testing. Because images rarely change, this could be an area where caching is preferred to pushing, but I’ll need an airtight config to fully weigh the trade-offs.

1 Like

To answer your question, I’ve had the following in a template for a while, now. It adds <link> tags instead of creating Link headers, but the process is largely the same.

{{ if .Content -}}
    {{ $urls := findRE "<img src=\"[^\"|\\\"]*\"" .Content -}}
    {{ range $url := $urls -}}
      {{ $url := (strings.TrimPrefix "<img src=\"" $url) -}}
      {{ $url := strings.TrimSuffix "\"" $url -}}
      <link rel="preload" href="{{ $url | htmlUnescape | safeHTML }}" as="image" />
    {{ end -}}
{{ end -}}

That said, I’m considering moving away from preloading images, because I have no data on if it actually helps pages load faster.

Setting <link rel="preload"> in the HTML tells browsers to start loading the resource for later use, which is a little different than using the Link header to indicate pushing. Some CDNs parse the HTML for <link rel="preload">, though, so it may not make any difference on Netlify.

In other words, I’m trying to figure out if pushing images is worth it too. I read somewhere that caching works with push, so a browser can tell the server it already has the resource. Looking at the Smashing Magazine article again, though, it seems better to only push CSS and maybe important JavaScript.

1 Like

So it turns out that Nginx has a way to set a cookie on page load, then http2_push based on the existence of that cookie. That way files are only pushed on the first visit to a page on the site, then allowed to load from the cache after that.

I submitted a question on Netlify’s support contact form to ask if they have a similar setup, since I couldn’t find anything in the docs. I’ll update this thread when I get a response.

Because of this post I tried to setup http/2 push but isn’t working for me (checked with browsers and nghttp).

I see the headers in the response though.

I checked the hugo site and isn’t working either. Is it actually working for you guys?

What about webfonts? I failed to see anyone do that in the few examples I looked online.

I have no data confirming this to be the correct way to do it, but I have my sites set up to push only the main font(s) used on a page, since I include some special fonts for code and such. And it only pushes the “regular” variant of the font, not italics or bold, since the browser can approximate the variants until the other font files download.

Also, and @butaca may find this useful, I heard back from Netlify. Their HTTP/2 Server Push feature is currently disabled due to a bug, and they said they would add me to a list to be notified when the feature is back up.

I think there was some miscommunication regarding pushing only on first visit, since I was given the suggestion to use service workers, a background JavaScript process that can be used, among other things, to download and cache resources before they are necessary. Thing is, that works better for something like an image slideshow, where the initial page has loaded and you’re asynchronously loading images. Not so much for CSS resources, since you want those available ASAP when the page loads. As far as I can tell, the service worker would be included as part of a JavaScript file which can be pushed but will not be parsed until the browser comes across it while loading the page.

So, I walked away from that conversation with the impression that that feature (the cookie, not pushing in general) is not and will not be available on Netlify.

I’m working on setting up my theme to include templates for generating configurations for common server setups, so I can look into Apache/httpd/.htaccess if people want. I currently have templates for Nginx and Netlify.


No wonder! I was scratching my head yesterday trying to figure out why HTTP2 Push was special… because the resource requests looked the exact same with or without the preload link tags :stuck_out_tongue:.

Please update this thread when you learn that Netlify has fixed that.


1 Like

Oh, that explains a few things… :man_facepalming:

Thanks for the info! :slight_smile:

I take this back. Looks like HTTP/2 Push is now working on Netlify.

  • Before enabling HTTP/2 push for fonts [waterfall]
  • After enabling HTTP/2 push for fonts [waterfall] (looks like I need to tone this down heavily to improve the First Byte Time :stuck_out_tongue:)

With Netlify, you need to define Link headers in their _headers file in order for server push to work. <link rel=preload> on the page won’t work. Which is nice, because I use that to indicate a non-essential CSS file can be loaded asynchronously.

I will update this thread when I get notified that Push is re-enabled. They’ll probably post something on their blog, too.

Seems like they work in my experience…


I use <link ..> for resources using Hugo Pipes because I don’t want to create a separate _headers custom output format just for that.

I like using netlify.toml for everything Netlify (config, headers, redirects), which I anyways cannot create using custom output format as that needs to exist as soon as Netlify clones the git repo.

Also, now I changed the Link headers to load only the regular variants of the fonts, and the First Byte Byte worsened even more! See

Looks like that FBT metric is completely random.


Looks like that FBT metric is completely random.


I simply re-ran the test (no change in Link headers this time) and now FBT improved from F to A… huh.

I meant that using link tags won’t cause Netlify to do Server Push for those files. At least, that is what I was told in those support emails. The link tags should still cause supporting browsers to make requests for those linked files, which seems to be happening in your screenshot. I don’t know how to interpret the various colors, though I doubt that’s using Netlify since they said the Server Push service is down.

I tend to use those tools to make sure I didn’t miss any potential optimizations, but use browser testing to see how fast the page actually loads, including using the browser’s developer tools to simulate bad network connections. If I can load at least as fast as popular websites and without a FOUC, I’m happy.

Hehe, I am pretty sure I am using Netlify… that screenshot is from my site.

May be their server Push is already up, and they didn’t notify you? Because I see a clear difference in the resource fetch timings.


OK, I don’t see the Link Header resources being pushed when I use the browser inspector (odd). So yeah, their Push service is really not working.

And as you said, my browser is simply requesting the js/css from the <link> tags.

Update 2:

Coincidentally I just got this reply from Netlify:

We are in the process of disabling server push as it is causing server instability for us. We’re working to re-enable it but it is not a high priority for us right now, so best to configure your site not to use it at present. I’ll be in touch when we have a fix so you can re-enable it.

1 Like