If you are a web developer && you don't live under a rock, you must have come across this buzzword called "SSG".
In the next 5 minutes, we will learn it down to the basics.
What is SSG?
Static Site Generation a.k.a. SSG is pre-rendering your React app into HTML at build time.
Let's break it down. Ideally, your React app is client-side rendered, meaning the user's browser will first download the complete JavaScript bundle and then execute it before the user can even see any content. Sounds pretty slow huh? It really is.
Pre-rendering to HTML means that we will convert the React Component to an HTML file and send the HTML file to the client so it can quickly show that to our user without much processing or bandwidth.
That's what server-side rendering is, you might be wondering.
Yes, it is, the Static in SSG comes from the fact that this whole process doesn't happen for each user request (like SSR) instead of at the build time, making SSG even faster than Server-side rendering.
In short, SSG will make the HTML pages out of a React app at the build time so it doesn't have to do it for every request, and neither does the browser have to do it on the client-side.
Why do we need SSG?
SSG exists to serve a specific use case, serving dynamic pages built in React as HTML.
What's the benefit you ask?
- SEO, search engine optimisation is one of the top benefits of doing SSG as it make indexing the pages easy for the crawlers.
- Speed: As you can guess, serving an HTML page is much faster for the end-user because the browser doesn't have to do much processing upfront. The pre-rendering makes it easy for the browser to fetch the HTML and render it straight up.
- Caching with CDNs: Building HTML pages opens the possibility for CDN caching to show its charm. The pages are stored closer to the user globally and hence can be accessed much faster. Every request doesn't have to wait for the server to render the page, it just receives the page from CDN, saving us compute resources and money.
Use case
While you can use SSG in any scenario as long as the page can be rendered at the build time, here are some popular use case patterns for SSG
- Marketing websites
- Blogs and documentation, like my own blog
- Portfolio websites
Tip: An easy way to know if you should use SSG is by answering: "Can you pre-render the page ahead of a user's request?" If the answer is yes, then you should choose Static Generation.
Using Next.js for SSG
Building Static pages with Next.js is simple. It works pretty similarly to building any other page i.e by creating a new file in the pages
directory.
A static page for a static route
Let's start by creating a static route ./pages/first-ssg.tsx
Because the page is rendered at the build time, Next.js needs to get all the data before the rendering. Next.js looks for a getStaticProps
method exported from the page to run at the build time. This method should return an object with props
key, which is passed to the Page component.
getStaticProps
should be used to fetch all the information needed to render the page. For example, if we are making an About company page, getStaticProps
is the right place to fetch company details from our API endpoint.
// ./pages/first-ssg.tsx
import type { NextPage } from "next";
export async function getStaticProps() {
// get all the data needed for rendering the page
const data = await fetchPageData();
return {
props: { data },
};
}
const FirstSSG = ({ data }) => {
return (
<main>
{/* more html content */}
</main>
)
}
export default FirstSSG;
Note:
getStaticProps
does not have access to the incoming request (such as query parameters or HTTP headers) because it runs at the build time and not at the request time.
A static page for a dynamic route
Let's create a dynamic route ./pages/[id].tsx
Apart from the getStaticProps
for page-specific data, Next.js now also needs to figure out what are all the possible paths for this route, because Next.js will have to render the pages for these paths at the build time.
For this purpose, Next.js expects a getStaticPaths
method which will list down all the possible paths for a dynamic route at the build time. For example, if it is a dynamic blog page we will need to list down all the available blogs as paths.
The paths
returned by getStaticPaths
contains a params
object which will be passed to the getStaticProps
. You can use the params
to pass the data about the path, like the blog slug or id, which can later be used by the getStaticProps
to get data for the page.
// ./pages/[id].tsx
import type { NextPage } from "next";
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } }
],
fallback: // true or false or 'blocking', to be discussed later
};
}
export async function getStaticProps({ params }) {
// get all the data needed for rendering the page
const data = await fetchPageData(params);
return {
props: { data },
};
}
// Your page layout
const FirstSSG = ({ data }) => {
return (
<main>
{/* more html content */}
</main>
)
}
export default FirstSSG;
That's all you need to do in order to build a Static website using Next.js.
It can't be all rosy, can it? Let's talk about some pitfalls.
Pitfalls
- One of the biggest drawbacks of this approach is the build time. If you have thousands of pages, building all of them will take a lot of time. I know there are solutions like Incremental Static Regeneration and
fallback
prop, which can be used in conjunction to get around this. We'll see this in a bit. - Another problem that can arise is outdated pages. Because you get the page data at build time, the data might be stale after some time. So you might have to schedule builds or trigger them at specific intervals to make sure data is the latest. This can also be resolved with Incremental Static Regeneration. However, if this is the case you should probably think about Server-side rendering and not Static pages for this route.
The fallback
option
As we discussed above, there is a fallback
option that can be returned from the getStaticPaths
and it is used for the paths which were not in the paths
list returned from getStaticPaths
.
It is important to understand the fallback option will not regenerate or update paths which were rendered at the build time instead it only works for the path not pre-rendered at build time.
The fallback
option can be extremely useful for apps with thousands of pages, making build time fast while keeping the user experience at best.
Why Next.js?
I prefer Next.js because it provides both the options,
- Server-side rendering
- Static site generation
So, I can choose while writing the page which way I want to go.
It also provides great integration with the Vercel cloud platform which allows edge-caching and CI/CD for free.
That's it for this one. I'll be writing another article explaining Incremental Static Regeneration soon. I hope you find this article helpful! Should you have any feedback or questions, please feel free to put them in the comments below. For more such articles, please follow me on Twitter
Until next time