174 lines
8.8 KiB
Text
174 lines
8.8 KiB
Text
---
|
|
title: Static Site Generation (SSG)
|
|
description: Use Static Site Generation (SSG) to pre-render pages at build time.
|
|
---
|
|
|
|
<details>
|
|
<summary>Examples</summary>
|
|
|
|
- [WordPress Example](https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress)([Demo](https://next-blog-wordpress.vercel.app))
|
|
- [Blog Starter using markdown files](https://github.com/vercel/next.js/tree/canary/examples/blog-starter) ([Demo](https://next-blog-starter.vercel.app/))
|
|
- [DatoCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-datocms) ([Demo](https://next-blog-datocms.vercel.app/))
|
|
- [TakeShape Example](https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape) ([Demo](https://next-blog-takeshape.vercel.app/))
|
|
- [Sanity Example](https://github.com/vercel/next.js/tree/canary/examples/cms-sanity) ([Demo](https://next-blog-sanity.vercel.app/))
|
|
- [Prismic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prismic) ([Demo](https://next-blog-prismic.vercel.app/))
|
|
- [Contentful Example](https://github.com/vercel/next.js/tree/canary/examples/cms-contentful) ([Demo](https://next-blog-contentful.vercel.app/))
|
|
- [Strapi Example](https://github.com/vercel/next.js/tree/canary/examples/cms-strapi) ([Demo](https://next-blog-strapi.vercel.app/))
|
|
- [Prepr Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prepr) ([Demo](https://next-blog-prepr.vercel.app/))
|
|
- [Agility CMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-agilitycms) ([Demo](https://next-blog-agilitycms.vercel.app/))
|
|
- [Cosmic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-cosmic) ([Demo](https://next-blog-cosmic.vercel.app/))
|
|
- [ButterCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-buttercms) ([Demo](https://next-blog-buttercms.vercel.app/))
|
|
- [Storyblok Example](https://github.com/vercel/next.js/tree/canary/examples/cms-storyblok) ([Demo](https://next-blog-storyblok.vercel.app/))
|
|
- [GraphCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-graphcms) ([Demo](https://next-blog-graphcms.vercel.app/))
|
|
- [Kontent Example](https://github.com/vercel/next.js/tree/canary/examples/cms-kontent-ai) ([Demo](https://next-blog-kontent.vercel.app/))
|
|
- [Builder.io Example](https://github.com/vercel/next.js/tree/canary/examples/cms-builder-io) ([Demo](https://cms-builder-io.vercel.app/))
|
|
- [TinaCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-tina) ([Demo](https://cms-tina-example.vercel.app/))
|
|
- [Static Tweet (Demo)](https://static-tweet.vercel.app/)
|
|
- [Enterspeed Example](https://github.com/vercel/next.js/tree/canary/examples/cms-enterspeed) ([Demo](https://next-blog-demo.enterspeed.com/))
|
|
|
|
</details>
|
|
|
|
If a page uses **Static Generation**, the page HTML is generated at **build time**. That means in production, the page HTML is generated when you run `next build`. This HTML will then be reused on each request. It can be cached by a CDN.
|
|
|
|
In Next.js, you can statically generate pages **with or without data**. Let's take a look at each case.
|
|
|
|
### Static Generation without data
|
|
|
|
By default, Next.js pre-renders pages using Static Generation without fetching data. Here's an example:
|
|
|
|
```jsx
|
|
function About() {
|
|
return <div>About</div>
|
|
}
|
|
|
|
export default About
|
|
```
|
|
|
|
Note that this page does not need to fetch any external data to be pre-rendered. In cases like this, Next.js generates a single HTML file per page during build time.
|
|
|
|
### Static Generation with data
|
|
|
|
Some pages require fetching external data for pre-rendering. There are two scenarios, and one or both might apply. In each case, you can use these functions that Next.js provides:
|
|
|
|
1. Your page **content** depends on external data: Use `getStaticProps`.
|
|
2. Your page **paths** depend on external data: Use `getStaticPaths` (usually in addition to `getStaticProps`).
|
|
|
|
#### Scenario 1: Your page content depends on external data
|
|
|
|
**Example**: Your blog page might need to fetch the list of blog posts from a CMS (content management system).
|
|
|
|
```jsx
|
|
// TODO: Need to fetch `posts` (by calling some API endpoint)
|
|
// before this page can be pre-rendered.
|
|
export default function Blog({ posts }) {
|
|
return (
|
|
<ul>
|
|
{posts.map((post) => (
|
|
<li>{post.title}</li>
|
|
))}
|
|
</ul>
|
|
)
|
|
}
|
|
```
|
|
|
|
To fetch this data on pre-render, Next.js allows you to `export` an `async` function called `getStaticProps` from the same file. This function gets called at build time and lets you pass fetched data to the page's `props` on pre-render.
|
|
|
|
```jsx
|
|
export default function Blog({ posts }) {
|
|
// Render posts...
|
|
}
|
|
|
|
// This function gets called at build time
|
|
export async function getStaticProps() {
|
|
// Call an external API endpoint to get posts
|
|
const res = await fetch('https://.../posts')
|
|
const posts = await res.json()
|
|
|
|
// By returning { props: { posts } }, the Blog component
|
|
// will receive `posts` as a prop at build time
|
|
return {
|
|
props: {
|
|
posts,
|
|
},
|
|
}
|
|
}
|
|
```
|
|
|
|
To learn more about how `getStaticProps` works, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/get-static-props).
|
|
|
|
#### Scenario 2: Your page paths depend on external data
|
|
|
|
Next.js allows you to create pages with **dynamic routes**. For example, you can create a file called `pages/posts/[id].js` to show a single blog post based on `id`. This will allow you to show a blog post with `id: 1` when you access `posts/1`.
|
|
|
|
> To learn more about dynamic routing, check the [Dynamic Routing documentation](/docs/pages/building-your-application/routing/dynamic-routes).
|
|
|
|
However, which `id` you want to pre-render at build time might depend on external data.
|
|
|
|
**Example**: suppose that you've only added one blog post (with `id: 1`) to the database. In this case, you'd only want to pre-render `posts/1` at build time.
|
|
|
|
Later, you might add the second post with `id: 2`. Then you'd want to pre-render `posts/2` as well.
|
|
|
|
So your page **paths** that are pre-rendered depend on external data. To handle this, Next.js lets you `export` an `async` function called `getStaticPaths` from a dynamic page (`pages/posts/[id].js` in this case). This function gets called at build time and lets you specify which paths you want to pre-render.
|
|
|
|
```jsx
|
|
// This function gets called at build time
|
|
export async function getStaticPaths() {
|
|
// Call an external API endpoint to get posts
|
|
const res = await fetch('https://.../posts')
|
|
const posts = await res.json()
|
|
|
|
// Get the paths we want to pre-render based on posts
|
|
const paths = posts.map((post) => ({
|
|
params: { id: post.id },
|
|
}))
|
|
|
|
// We'll pre-render only these paths at build time.
|
|
// { fallback: false } means other routes should 404.
|
|
return { paths, fallback: false }
|
|
}
|
|
```
|
|
|
|
Also in `pages/posts/[id].js`, you need to export `getStaticProps` so that you can fetch the data about the post with this `id` and use it to pre-render the page:
|
|
|
|
```jsx
|
|
export default function Post({ post }) {
|
|
// Render post...
|
|
}
|
|
|
|
export async function getStaticPaths() {
|
|
// ...
|
|
}
|
|
|
|
// This also gets called at build time
|
|
export async function getStaticProps({ params }) {
|
|
// params contains the post `id`.
|
|
// If the route is like /posts/1, then params.id is 1
|
|
const res = await fetch(`https://.../posts/${params.id}`)
|
|
const post = await res.json()
|
|
|
|
// Pass post data to the page via props
|
|
return { props: { post } }
|
|
}
|
|
```
|
|
|
|
To learn more about how `getStaticPaths` works, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/get-static-paths).
|
|
|
|
### When should I use Static Generation?
|
|
|
|
We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.
|
|
|
|
You can use Static Generation for many types of pages, including:
|
|
|
|
- Marketing pages
|
|
- Blog posts and portfolios
|
|
- E-commerce product listings
|
|
- Help and documentation
|
|
|
|
You should ask yourself: "Can I pre-render this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation.
|
|
|
|
On the other hand, Static Generation is **not** a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request.
|
|
|
|
In cases like this, you can do one of the following:
|
|
|
|
- Use Static Generation with **Client-side data fetching:** You can skip pre-rendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/client-side).
|
|
- Use **Server-Side Rendering:** Next.js pre-renders a page on each request. It will be slower because the page cannot be cached by a CDN, but the pre-rendered page will always be up-to-date. We'll talk about this approach below.
|