Incremental Static Regeneration
Static sites and Headless CMS: The challenge of Strapi implementation with Nextjs
|
8 minute read

The Challenge of Choosing the Right CMS
In the ever-evolving world of web development, businesses frequently encounter problems to harmonize the demands of a static site's SEO and speed with the necessity for a flexible and easy-to-use content management system (CMS). This balancing act becomes particularly pronounced when frequent content updates are required. Recently, one of our clients faced a similar challenge and they reached out to us. Their specific technical requirements asked for a statically-generated site for its SEO advantages in the public-facing part of the app. Yet, their business model calls for frequent updates of the content. Our team had to decide which CMS to use, and how to combine those conflicting concepts.
Choosing Strapi
To meet the client’s requirements, we chose Strapi, an open-source headless CMS known for its adaptability and robust API capabilities. Strapi empowers developers to create and manage dynamic content effortlessly, providing the flexibility needed to keep pace with evolving business requirements.
In order to combine the dynamic capabilities of Strapi with the performance benefits of a static site, we also turned to Next.js, a popular React framework. Next.js facilitates server-side rendering (SSR) and static site generation (SSG), enabling the creation of dynamic and engaging user interfaces while ensuring optimal performance. By leveraging the strengths of both Strapi and Next.js, we could seamlessly integrate dynamic content management with the speed and SEO advantages of a static site architecture.
Benefits of Strapi CMS
Strapi stood out as a powerful and customizable headless CMS solution, which empowers developers to create dynamic and scalable content-driven applications with ease. What set Strapi apart, in our case, is:
Flexible Content Architecture: Allowed us to define custom content types tailored to our specific project needs.
User-Friendly Admin Panel: Easy for non-technical users to manage content.
Support for RESTful and GraphQL APIs: Versatile options for data fetching.
Open-Source Nature: Permitted extensive customization of functionality, providing our client with flexibility and control over their content management processes.
Using Strapi’s flexible content structure, we created all necessary content types, including pages, sections, and components. Strapi enabled us to create reusable components and sections within the CMS and use them on any page. The components included the navbar, footer, SEO component for pages’ metadata, and so on.
We also extended Strapi’s functionality via its plugins and extensions. For example, we included a rich text editor, which was very useful in the blog feature of the app, and an image optimization plugin that converted all images to the .webp format.
Strapi offers various deployment options to suit different project requirements and preferences. For our project, we chose a self-hosting approach and deployed Strapi on our client’s infrastructure on Azure. We utilized several Azure services to ensure optimal performance and scalability:
App Service - used to host the Strapi application
Azure Database for PostgreSQL - stores the content in a PostgreSQL database
Azure Storage account - stores the assets such as images
Azure CDN connected to the Storage account - serves the app’s images
Building the Static Site with Next.js
To build our static site, we turned to Next.js, a powerful React framework that simplifies the process of creating dynamic and high-performing web applications. Next.js offers several key features, providing us with the tools needed to create a modern, interactive, and SEO-friendly web experience:
Server-Side Rendering (SSR)
Static Site Generation (SSG)
File-Based Routing System
Bonus points were awarded to Next.js for its built-in support for CSS modules, TypeScript, and various data fetching methods, making it a versatile choice for our project.
Understanding SSR and SSG
In Next.js, server-side rendering (SSR) and static site generation (SSG) are two powerful approaches to rendering web pages with distinct advantages and disadvantages.
SSR dynamically generates HTML on each request, allowing for real-time data fetching and personalized content delivery. This results in the latest data being shown on the page but might result in slower load time, since the server needs to generate HTML on every request. There is also the issue of server load, especially on high-traffic sites, which cannot be overlooked.
On the other hand, SSG pre-generates HTML at build time, resulting in faster page loads and improved SEO as pages are served as static assets. SSG is ideal for content-heavy websites with relatively stable data that doesn't require real-time updates.
To deploy our Next.js application we have, again, turned to Azure and its App Service which took care of automatically scaling our application worldwide. That mitigated the bottleneck problem of developing an SSG site.
Achieving the Best of Both Worlds with ISR
Ideally, we wanted the best of both worlds: statically generated pages, served to the user with the latest data in the CMS, ensuring the best possible load times, SEO optimization, and data accuracy. But is that possible? The answer is yes, with a feature from Next.js called ISR or Incremental Static Regeneration.
What is ISR - Incremental Static Regeneration?
When using the SSG rendering strategy in Next.js, pages are cached and served as static content. Unlike other SSG-enabled frameworks that require a complete frontend app rebuild to update cached data, Next.js allows developers to rebuild individual pages. This feature, called Incremental Static Regeneration (ISR), offers two strategies:
Time-Based Revalidation - a time parameter can be defined on each page, regenerating it once that time has elapsed. This is useful as a backup revalidation technique, having the page revalidate every 24 hours, for example.
On-Demand Revalidation - a different strategy that manually revalidates a specific page based on an event. This, for example, can be a form submission or even an HTTP request.
In our case, on-demand revalidation was the better-suited strategy, as it allowed us to revalidate specific pages whenever their content changed in the CMS.
Solution: Strapi & webhooks + Next.js & Node.js
We implemented a solution where Strapi sends notifications to our Next.js application whenever the content is updated. This triggers the ISR process for the pages affected by the content changes.
Implementation steps
1. Create a Revalidation Endpoint
To implement this, we started by creating a revalidation endpoint in our app. Next.js comes with the ability to run a Node.js server alongside the Next.js app. Those are specified in the /pages/api directory. We created a revalidate.ts file in that directory, which creates a /revalidate endpoint. In that file, we wrote revalidation logic similar to this:
2. Utilize Strapi Webhook Requests
Strapi webhook requests contain a certain body structure that is predefined. We used the model and entry properties of that body to figure out which content type and which exact entry within that content type has changed.
3. Specify Paths for Revalidation
Based on the value of the model property, we could specify which path to revalidate. For dynamic paths, we supplemented that with values of the entry property, which contains data of the changed entry.
In our case, we constructed the exact path to the blog that needs revalidation by first checking if the model property indicated that a certain blog has changed. If that were true, we would construct the exact path to that blog, by using that blog’s new data that has been returned to us as the entry property of the HTTP request.
4. Revalidate Paths
Our requirements specified that one entry in Strapi could have multiple paths in our app, so we returned the constructed paths in an array. To revalidate those paths, all we needed to do was go through the array and call the revalidate() function that’s part of the response of type NextApiResponse. This function takes the exact path that needs to be revalidated as an argument, and regeneration is handled by Next.js under the hood.
5. Set Up the Webhook
All that was left to do was to set up the webhook. Navigating to settings in Strapi, we find a Webhooks menu. From there we can create a new webhook, name it, and point it to our /revalidate endpoint, adding the secret as the query parameter so our revalidation request would be valid. The webhook URL looks something like this:
https://{APP-DOMAIN}/revalidate?secret={REVALIDATION-SECRET}
We also specified that this webhook would only be triggered by the update event on a Strapi entry.
Note: ISR cannot handle creating new pages from new entries in Strapi. This is handled by the getStaticPaths function and its fallback prop. Setting fallback to true allows the generation of new pages upon the first request instead of showing a 404 error page.
Results
Implementing our approach resulted in a seamlessly synchronized content update process between Strapi and the Next.js application. Key outcomes included:
Content changes are reflected across the website within a few seconds, without compromising performance or user experience.
Selectively regenerating only the affected pages avoids unnecessary rebuilding, optimizing resource utilization and minimizing downtime.
Users enjoy a dynamic browsing experience with up-to-date content.
Clients benefit from streamlined content management and efficient utilization of Next.js's static site generation capabilities.
Overall, this integration enhanced the agility of the web application, ensuring it remains responsive to content changes and adaptable to evolving client’s business needs.



