Pre-Rendering

What is Pre-Rendering?

Next.js pre-renders every page. All HTML is generated in advance, instead of having this all done by client-side JavaScript. This can give your application better performance and also SEO.

Generated HTML is associated with as little JavaScript code as needed for that page. When the browser loads a page, the JavaScript code runs and makes the page fully interactive. This process is called hydration.

We are going to discover multiple ways of pre-rendering. When using Next.js, you can always choose with for you would like to use for every separate page.

Static Generation

What is Static Generation?

Static Generation means that the HTML is generated at build time and will then get re-used on each request.

  • This is the recommended method of pre-rendering, because it is better for performance. It is better for performance because statically generated pages can be cached by a CDN, without extra configuration.

Static Generation with Data

When external data is required, you can work with pages.

Scenario One: Page content depends on external data - getStaticProps

A good example of this is when you have a blog and you want to fetch a list of blog posts from your CMS.

You can fetch this data on pre-render by exporting an asynchronous function called getStaticProps. This is a function that gets called at build time and will let you pass the fetched data to the props on that page during pre-render.

Example Function

function Blog({ posts }) {
  // render posts ...
}

// function that gets called at build time
export async function getStaticProps() {
  // call an external API endpoint to get the blog posts
  const res = await fetch('http://.../posts')
  const posts = await res.json()
  
  // when you return { props: { posts } } the Blog component will
  // receive `posts` as a prop at build time
  return { 
    props: {
      posts,
      },
    }
}

export default Blog
Scenario Two: Page Paths depend on external data - getStaticPaths

As mentioned before, you can create dynamic routes by just creating pages.

Example: if your file is called pages/posts/[id].js, and it shows a single blog post, this will show a blog post with the id: 1 when you access posts/1.

But, what id you want to render at build time can depend on external data.

You can export another asynchronous function called getStaticPaths when using it in dynamic pages. This function gets called at build time and can let you specify what paths you want to pre-render.

// function gets called on 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 the posts
  const paths = posts.map((post) => (
    {
      params: { 
        id: post.id 
      },
    }
  ))
  // pre-render only these paths at buildtime
  // { fallback: false } means other routes should 404
  return { paths, fallback: false }
}

In combination with the above function, you will need to export the getStaticProps function so you can fetch the data about the post with the id and use this to then pre-render the page.

When do you use Static Generation?

It is recommended to use static generation whenever it is possible, no matter if you have data or not. This is because your page can be built once and then served by CDN, this makes it much faster than using a server to render every request.

Ask yourself if you can pre-render this page ahead of a user's request, if so, use static generation.

But, it is not a good idea to use static generation when you can not pre-render a page ahead of a user's request. This can be because the data gets frequently updated. When this is the case, you can use static generation with client-side rendering by skipping the pre-rendering of some parts of a page and use the client-side of JavaScript to populate this. You can also use server-side rendering instead, although this makes the page slower in performance.

Server-side Rendering

What is Server-side Rendering?

Even though static generation is recommended, there is sometimes a possibility that Server-side Rendering is a better choice.

When using server-side rendering on a page, you can export the asynchronous function getServerSideProps. This function gets called by the server on every request.

function Page({ data }) {
  // render data
}

// gets called on every request
export async function getServerSideProps() {
  // fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()
  
  // pass data to the page via props
  return { 
    props: { 
      data 
    }
  }
}

export default Page

External sources

Images from Next.js learn