Speeding up our pages with NextJS ISR

Paul Corbett
Engineering the Skies: Qantas Tech Blog
3 min readJun 20, 2023

As developers, one of the things we always strive for is to make our sites faster. It’s reported that one in four visitors to a website will abandon their visit if it takes more than four seconds to load. Even a one second delay can lead to a decrease in customer satisfaction. On an e-commerce site, this has an added effect of impacting revenue — something nobody wants.

One of the improvements we wanted to make with Jetstar Holidays was to look at ways we could improve our load time. Across our five most visited pages we had an average time to being interactive of 5.6 seconds. According to our Lighthouse score we also averaged a low performance score of 52.8/100 (where the higher the better) across those same pages.

Using NextJS ISR

At the time we were using NextJS version 11 with all our pages rendered server-side on initial load. Each page would have to make four to five API calls to retrieve content from our CMS or our property and availability services. The majority of which was content that was very rarely updated such as property details.

What we wanted to do was utilise NextJS’s incremental static regeneration (ISR) ability. From their docs:

Next.js allows you to create or update static pages after you’ve built your site. Incremental Static Regeneration (ISR) enables you to use static-generation on a per-page basis, without needing to rebuild the entire site. With ISR, you can retain the benefits of static while scaling to millions of pages.

While we don’t have millions of pages, with all destination and property pages we were close to 1,000 pages that we could look to improve.

Static generation means that the HTML for our pages is created at build time. The server would then render that HTML with API calls to our availability services used at runtime to load up-to-date pricing.

Overcoming build time hurdles

Yet we had a problem. All our pages loaded data from our backend-for-frontend (BFF) service. That service was built into NextJS API routes which cannot be called at build time as they don’t yet exist. This meant we had to restructure all our API calls so that when we fetch the data using `getStaticProps` it was done directly rather than via our BFF. This is where most of our refactoring occurred as we transitioned from using getInitialProps to getStaticProps.

We also had to take into account what happens when content is updated. By setting a revalidation prop in getStaticProps we could ensure that after the set period NextJs would attempt to regenerate the page and cache this version. While the user that triggered the regeneration would not see the updated content, the next user to visit that page would. Under normal circumstances this would have minimal consequences, but Jetstar Holidays regularly has flight campaigns that commence at midnight. We were finding that pages weren’t being generated until early morning. To remedy that problem we used our build pipeline to create a build at 12:00 am every day (we were already running every other day to update another service anyway.) HTML for those campaign pages would then be readily available.

The outcomes

There were two positive outcomes to this piece of work. As developers we were able to upgrade NextJS, something we’d been planning to do as tech debt but never able to factor in the time to do so.

More importantly we were able to speed up the Jetstar Holidays site to give our customers a better experience.

  • Our average load time had gone from 5.6 seconds to 4.22
  • Campaign pages saw a 2.3 second reduction from 5.9 to 3.6 seconds
  • Average performance score jumped from 52.8 to 73

Final thoughts

While there are further improvements we can make to our site performance, this was our first step in giving our customers the best experience they can have when booking their next getaway with Jetstar Holidays.

Information has been prepared for information purposes only and does not constitute advice.

--

--