Next.js has become a staple of a React developer’s toolkit for many good reasons but one we will focus on today is its assortment of rendering methods. In total, there are four rendering methods: Client Side Rendering (CSR), Server Side Rendering (SSR), Static Site Generation (SSG), and Incremental Static Regeneration (ISR).
In this post, we’re going to be focusing on SSG and SSR because they’re the two most common and arguably most important rendering methods used in Next.js today. We’re going to compare them head-to-head to see the benefits and drawbacks of both, as well as when to use them in your applications.
Rendering methods in Next.js
SSR vs SSG vs CSR vs ISR
But, before jumping into our comparison of SSG vs. SSR, it’s important we understand all of the rendering methods Next.js offers to give our comparison more context. So, here is a quick overview of each one in case you’re not familiar with them.
- CSR: In this rendering method, content is rendered in the browser on the client with JavaScript. The browser receives a bare-bones HTML document from the server and then JavaScript fills in the gaps by fetching data. Learn more about CSR by reading our in-depth guide.
- SSR: With SSR, all the rendering is done on the server at request-time. For every request, the server assembles any fetched data and the HTML document and sends the client a complete document ready to render to the user. The key thing to note here is that the server builds and renders a new page for every request made so for high traffic levels this can be resource-intensive. Learn more about SSR with our in-depth guide.
- SSG: In terms of rendering, SSG and SSR are nearly the same. The one big difference is that SSG does all of its rendering before the user requests a page. Instead, it does it at build time and then the complete HTML document is then served from a CDN to improve performance for users. Because SSG fetches data and builds it into an HTML page once and then reuses that output for all requests to that page until the next rebuild of the site, it can be considerably less resource-intensive than SSR.
- ISR: ISR addresses one possible challenge with SSG, which is the need to rebuild your entire website to update a page’s content. With content updating frequently (e.g., on a blog), SSG might cause you to rebuild the entire site very frequently for changes contained to a single page. ISR allows you to rebuild only the updated pages after the original site build.
First time here? Discover what Prismic can do!
👋 Meet Prismic, your solution for creating performant websites! Developers, build with your preferred tech stack and deliver a visual page builder to marketers so they can quickly create on-brand pages independently!
Static Site Generation (SSG)
SSG has grown in popularity in recent years with Jamstack’s surge in popularity and for many good reasons that we’ll cover in the coming sections. But, let’s start by getting some context: what is SSG in the context of Next.js?
Well, similar to the definition earlier, it’s a way to pre-render a page's content at build time, so when a user requests the page, the CDN responds with the pre-generated HTML file.
How does it work?
If you want to use SSG in your Next.js application, all you need to do is export a function called getStaticProps from the page you want to use SSG on. Then, when Next.js sees this function exported, it knows to generate that page using SSG when building the website using next build. You can also pass props directly to the client-side page by returning a props object from the getStaticProps function.
For standard pages that have a single route, getStaticProps on its own is all you need. However, a common use case is to use SSG for content like blog posts where one page will cover multiple routes using dynamic routes in Next.js. If this is the case, you’ll also need to export a getStaticPaths function alongside getStaticProps; this allows Next.js to also pre-render all the paths specified by getStaticPaths using SSG as well. Here are the examples of these functions that Next.js provides:
export async function getStaticPaths() {
return {
// The paths to be pre-rendered at build time. E.g. /post/1, /post/2, etc
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
}
}
export async function getStaticProps(context) {
return {
// This props object will be passed to the page so they can be used on the frontend.
props: {},
}
}
Benefits of SSG
There are a few key benefits to note for why you might want to use SSG:
- SSG pages are always online once they’re generated and distributed to a CDN. This means your backend server or data source doesn’t need to be available all the time for the page to function. Even if they go offline for a bit, your website will still be available and ready to use.
- SSG pages are generally easier to scale to handle increased traffic demands because they’re just static files on a CDN and don’t require servers at runtime like SSR websites do to render pages, etc.
- Pages generated with SSG are faster to render. This is because the HTML is already generated ahead of time so the user doesn’t need to wait for the server to generate the HTML on demand. Instead, they just get the completed HTML and render it.
Drawbacks of SSG
Unfortunately using SSG isn’t the solution to all problems and there are a couple of drawbacks to keep in mind.
- On their own, SSG pages can’t change content without the site being rebuilt and redeployed entirely. So, even if you make just one small typo, the entire website needs to be regenerated and deployed to get a correction live. With a few pages, this isn’t a big issue, but as your site grows so does its time to build, which could be a problem if you need to update content often.
- Secondly, because the pages are generated ahead of time before any requests happen, SSG pages don’t have direct access to requests to access things like HTTP headers and query parameters at build time. So, if you want to access these, you have to write custom middleware in addition to SSG.
When should you use SSG?
It can be tricky to know what rendering method is best to use and for when but there are a couple of factors that help indicate that SSG is the best candidate. Let’s take a look at each of these.
If performance is a high priority and all the required data for the page is available at build time then SSG is a great choice. For example, a website using a headless CMS would be an ideal candidate for SSG. This is because all the page data is available prior to any requests being made, meaning they can be generated and cached for fast loading times.
SSG as a whole leads to very fast loading times, which while making your users happy, will also help your website’s SEO improve since search engines love fast and responsive websites that are quick for users to interact with.
However, if you have a high volume of data that updates very frequently, or if it’s critical to have the latest data available to users (like stock levels on an e-commerce site), then SSG may not be suitable because it needs a complete rebuild each time data changes. In this situation, something like ISR or SSR would be a better choice.
Server-side rendering (SSR)
Where SSG can’t be used for some reason, people often turn to SSR because it largely solves the issues with SSG, but unfortunately, it does have some of its own drawbacks, as we’ll see in a moment. As covered earlier, SSR is similar to SSG in the sense that pages are generated on a server but the key difference is when the rendering happens. With SSR, pages are rendered at request time for every request.
If you’re interested in learning more about SSR in general, make sure to check out our in-depth blog post on it.
How does it work?
Setting up SSR in a Next.js application is pretty much the same as setting up SSG. All you need to do is export an async function called getServerSideProps from the page file you wish to add it to. This function is then called every time the page is requested and the output of it is the props used to generate the page.
Functionally speaking, getServerSideProps is similar to the getStaticProps function used to generate SSG pages. But, the key difference as noted above is getServerSideProps is run on every request instead of once at build time. Here’s an example from the Next.js documentation:
export async function getServerSideProps(context) {
return {
// This props object will be passed to the page so they can be used on the frontend.
props: {},
}
}
Benefits of SSR
While SSG is often the go-to for many people due to its own benefits, SSR poses its own unique benefits that make it a great choice as well.
- SSR pages will always display the latest data because they are generated on the server in response to every request. This means you can fetch the latest data from APIs every time someone requests a page to ensure you’re always displaying the latest data.
- If you need access to the page request for things like URL parameters or HTML headers, then SSR makes this easy since they’re all included in the request object for you to use.
- Finally, because we have access to the request and we generate the page in response to a user’s request, we can serve users unique pages and content based on that request and any data we can fetch about the user such as their preferences.
Drawbacks of SSR
Unfortunately, as is the case with many things, SSR isn’t all sunshine and rainbows, and it does have a few drawbacks that need to be taken into account.
- SSR is slower at displaying a page than SSG. This is because SSR generates each page per request where SSG can move that entire process to the site build time before user requests are made. During the generation process, there are also external factors that could influence your page loading speed like fetching data from external APIs. If the APIs are slow to respond, your page generation and in turn loading times will suffer.
- Similar to the last point, using SSR will lead to higher TTFB (Time to First Byte) metrics. This is because this metric and some other Core Web Vitals metrics are measured on the initial page rendering and loading times.
- Finally, if you want to cache your SSR pages to improve their loading times, you’ll need to implement this logic and functionality yourself. This wouldn’t be too bad until you realize that SSG pages are cached automatically in comparison.
When should you use SSR?
Even with the drawbacks, there are times when using SSR is the best choice. Let’s take a look at two of them.
Access Page Requests
If you need to access data from a page request or perform extra logic off the back of the request, like hitting an API based on a query parameter, then SSR is the clear choice since you can easily implement this functionality without needing to write custom middleware.
Request Time Data Fetching
If you need your page to be based on data that can only be obtained at request time then SSR makes sense. For example, a lot of applications built using Next.js will use SSR for pages behind authentication because they can’t be pre-rendered using SSG, and they need to perform additional logic based on the requests, like checking that cookies are valid from the request headers or needing to validate data provided against a database.
SEO considerations
Although they both have their own benefits and drawbacks, SSG and SSR are both great for SEO. This is because both of them generate their HTML outputs on a server, meaning both can easily be crawled and indexed by search engine bots.
Both rendering methods also render pages quickly, which helps with SEO rankings. However, out of the two, SSG will render pages faster due to having a faster server response time because its pages are built ahead of time before the user requests anything.
So, with this in mind, if you have particularly large pages that have a lot of assets or data to be fetched/processed when building the page consider using SSG. This allows you to leverage its faster server response times which in turn will lead to faster page rendering and therefore positively influence the SEO scores of that page.
SSR does have its own benefits over SSG though. Because SSR rebuilds pages every time a user visits them it means new content can be surfaced to search engines sooner as no rebuilds are required like they are for SSG. This is a particularly noteworthy benefit for websites that have a lot of content updates that might not want to be constantly rebuilding their website.
However, it’s worth noting that Next.js’s ISR does largely solve this issue for SSG because it allows for the incremental rebuilding of individual static pages without needing to rebuild the entire website. But, in a straight SSR vs SSG conversation, this is a point to be aware of.
To summarise, SSG has faster server response times that can lead to faster page rendering times and SSR can surface content changes potentially sooner to search engines (although SSG can do this as well with ISR). But, outside of these differences, SSG and SSR are pretty much identical for SEO purposes and both will help improve the SEO of your website over other rendering methods like CSR.
My rule of thumb
In closing, both SSR and SSG are great rendering methods and have their own pros and cons that make them suitable for different scenarios in a Next.js application. Overall one isn’t better than the other and it’s almost like comparing apples and pears; they have similarities but also have different purposes, so it’s important to know how and when to use both methods.
But, to help you decide on which rendering method to use and when, I generally follow this: Where possible look to use SSG, but if that’s not possible for some of the reasons above, then use SSR for the page.
Finally, if you want to dig deeper into the topics we’ve covered in this post, you might be interested in reading some of our other posts on rendering methods, such as: