Dynamic websites are slow. Why are they so prevalent?
The majority of teams building websites for clients use some kind of dynamic CMS: WordPress, Umbraco, and Drupal are some of the most common names that pop up when discussing traditional websites. The frontends are usually strongly tied to the backend and have some kind of templating system that can harness the power of the language used for the backend – generally PHP or C#.
These CMS’ are used because they solve most of the common problems in development right out of the box, and are fairly easy to extend for custom features. They’re also easy to use for clients, with flexible content management systems that are complex enough to perform a wide range of functions while being simple enough for a non-technical user to understand. If your client wants to make a content change on a certain page, they just need to click ‘publish’ and the website is immediately updated.
However, there’s an issue with these systems being so widespread: Most of the websites we build for clients have no need to be dynamic, and as a result they don’t perform as well as they could do if they were static.
In my experience, the most common type of website you’ll build consists of pages with flexible content blocks, and perhaps a blog section. Applications or platforms with login areas and customised content for each user are much less common for the average agency WordPress or Umbraco developer.
This makes sense if your website requires authentication and customised content for each user; however, if you’re just displaying some static content, why do we need this wait time? Why not just make these sites static, drastically improving performance and in turn SEO?
Incremental Static Regeneration
The problem with static websites is that… well, they’re static. Once they are built, that content won’t change until they are rebuilt, which can take a lot of processing power for sites with many pages. There is also the problem of who builds the site: If the client doesn’t have a good understanding of building their site, things could go wrong, and if there are errors in the build they will end up going back to the developers anyway. If the developers need to handle the builds every time, that’s an extra cost for the client or time wasted for the devs.
It’s a hell of a mouthful, but the way it works is fairly simple: Next.js runs on the server and builds static webpages from your project, using the
getStaticProps function to fetch data from APIs. Each page is provided with a
revalidation timer, which is the number of seconds before it will try to rebuild the webpage.
However, it doesn’t just blindly rebuild every single page on your site: Instead, it re-runs the API fetch requests and checks if the data has changed compared to the previous build. If it has the page will be built again, but if not the page is left alone, allowing the server to optimise it’s processing time. To optimise even further, these rebuilds will only be triggered once a user visits the page.
This means that the first visitor to a page that’s passed its revalidation timer will be served the old version of the page, so nobody ever needs to wait a long time to load a page. Once the page has finished building, subsequent visitors will receive the newly built page.
This leaves one final problem: The first user to visit the page will still receive outdated data. This might not be a problem for some websites, but for things like policies it can have legal implications. Thankfully, there are solutions to this problem as well: For one, you can just revalidate the data again once the user is on the page. If the fetch request is triggered as soon as they reach the page, there might just be a split-second where the content changes to the new version, but most of the time this change is unnoticeable. Packages like React Query offer simple hooks to revalidate your back-end requests.
When not to use ISR
The main pitfall of Incremental Static Regeneration is the lack of personalised content for different users: a static page is the same for everyone who visits it.
With that said, there is some potential for solving this pitfall. If your website is only partially personalised – perhaps there’s a user area or a way of posting comments – we can use a combination of on-page requests with HTTP-only cookies to handle authentication, leaving these sections blank until React (or a similar framework) has the data it needs to display the content.
In this way, we can have the best of both worlds: a super-fast, semi-dynamic website without the need for sluggish server-side rendering. It’s also possible to go half-and-half with Next.js – some of your pages can be dynamic, and some can be static. It all depends on how you set up your
What if I’m not using Next.js?
What’s surprising to me is that I’ve not come across this approach in other frameworks and CMS’: It seems like a language such as PHP or C# would be able to handle this static regeneration business. The truth is that I’m probably just ignorant to backend frameworks that do offer this functionality. I do think it’s a little strange that something like WordPress or Umbraco doesn’t have a plugin at the very least that can do this – at least, I’ve not come across it at work. With that said, there’s an awful lot I don’t know about backend development – so let me know in the comments if you’ve come across something like this. I’m sure Next.js is not the first product to make this possible.
Perhaps for now it’s an approach best suited to JAMstack and consuming REST APIs, as with them we have the ability to re-fetch data to ensure everything’s up-to-date. It’s an extra step to build an API for your system – although even WordPress offers a REST API without any additional configuration.
I do stand by my original statement, however: Agency developers tend to build way too many dynamic sites that have no business being dynamic. I hope that this methodology will grow more traction so we can build more competitive sites for our clients. In the meantime, spin up Next.js and have a go: I’ve written a quick guide for getting up and running with Increment Static Generation and React Query.