Hugo Performance Improvements

Hugo Performance Improvements header image

A while back I migrated my blog to Hugo. Ever since that migration, I tried to get even more performance out of my template. So far I didn’t do much, right up until I read up on some tips & tricks the last few weeks. So what follows is a set of ‘best practices’ I applied to my template. Some of them borrowed from the post How I improved my Jekyll SEO. Others found on the web. You can find the results of my changes to the template on the fork I made on GitHub.

Performance updates

I used the Pagespeed Insights as a metric to measure what could be improved. But not all changes are related to speed. Some of them are for SEO, others because it ‘looked’ better. All in all, I went up from around 60 to 99 on mobile and a 100 on desktop. You can easily check your site on Pagespeed Insights yourself.


I wanted to load WEBP images for performance reasons. However right after rebuilding everything I figured out they are not supported on the iPhone. Currently, Hugo does not support a solution to recompile images. But I do store everything myself in both .png and .webp. That means that I only had to update my template to support both images. Waldek pointed out on Twitter that you can achieve that using the <picture> element. So the images in my template are set-up as followed:

        <source srcset="{{.Params.image | absURL}}" type="image/webp">
        <img src="{{replace .Params.image ".webp" ".png" | absURL}}" alt="{{ .Title}} header image"></source>

As of Hugo 0.62 you can even change the HTML rendered from your markdown. To do so you need a Render Hook. I added a new file in my template folder under /layouts/_default/_markup/render-image.html. Added the same picture element:

    <source srcset="{{ .Destination | safeURL}}" type="image/webp">
    <img src="{{replace  .Destination ".webp" ".png" | safeURL }}" alt="{{ .Text }}"></source>

Now even images in your MD files will be processed as you wish. Do make sure to have both a png file and a webp file though.

RSS settings

By default, Hugo will update the RSS feed with any change to pages. Something that can easily be fixed by adding a custom RSS template. That same template can be used to add the appropriate image for Feedly (they don’t support webp either). For Feedly I did add an image tag into the description:

    {{ range first 15 (where .Site.Pages "Type" "post")}}<item>
      <title>{{ .Title }}</title>
      <description>{{if .Params.image }}{{ htmlUnescape "<p><img src="}}"{{ replace .Params.image ".webp" ".png" | absURL}}" class="webfeedsFeaturedVisual" {{ htmlUnescape "/></p>" }} {{ end }}


The biggest hit when checking my speed was the use of Disqus. It really is a slow solution. However, I did not want to give it up as adding comments definitely adds value. I ended up implementing Lazy-loading Disqus. This forces to load when the window is visible, improving the mobile view for end-users. My partial looks like:

<div class="disqus"></div>
<div class="disqus-loading">Loading comments&hellip;</div>

<script src="{{ "js/disqusloader.js" | absURL}}"></script>

            scriptUrl: '//{{ .Site.DisqusShortname }}',
            disqusConfig: function () {
       = '{{ .Permalink }}';
       = '{{ .Permalink }}';
                this.callbacks.onReady = [function () {
                    var el = document.querySelector('.disqus-loading');
                    if (el.classList)
                        el.classList.add('is-hidden'); // IE 10+
                        el.className += ' ' + 'is-hidden'; // IE 8-9


Generic improvements

Definitely check-out the post How I improved my Jekyll SEO by Waldek. I used the same improvements for my Twitter cards. Besides all those changes I removed some un-used Javascript and CSS and that’s about it. I went up to a solid 99 on mobile and 100 on desktop. The next stop is either including search or implemented bundling.

Loading comments…