Data Fetching

What is Data Fetching?

Data fetching is used to make pre-rendering and rendering possible on pages. There are three unique ways Next.js fetches data:

  1. Static Generation - getStaticProps

  2. Static Generation - getStaticPaths

  3. Server-side Rendering - getServerSideProps

Static Generation - getStaticProps

You can export the asynchronous function getStaticProps from a page and Next.js will pre-render this page at build time using the props that get returned from the function.

Parameters for getStaticProps

getStaticProps has one parameter, which is an object and can contain the following keys:

  • params

    • This key is the route parameter that pages use for dynamic routes.

    • Let's say a page name is [id].js, the params will look like { id: ... }.

    • This key should be used together with getStaticPaths.

  • preview

    • This key is true if the page is in preview mode.

    • This key is undefined in any other case.

  • previewData

    • Contains a preview data set by setPreviewData

  • locale

    • Contains the active locale.

    • This is if you have enabled internationalized routing.

  • locales

    • Contains all supported locales.

    • This is if you have enabled internationalized routing.

  • defaultLocale

    • Contains the configured default locale

    • This is if you have enabled internationalized routing.

Returns for getStaticProps

  • props

    • Optional

    • Object with the props that will be received by the page component

    • Should be a serialized object.

  • revalidate

    • Optional

    • Amount in seconds after which a page re-generation can occur.

    • Default is `false`, which means no revalidation.

  • notFound

    • Optional

    • Boolean value to allow the page to return a 404 status and page.

    • Example:

// inside of getStaticProps function
if (!data) {return {notFound: true,}}
  • redirect

    • Optional

    • Example:

{ destination: string, permanent: boolean}

When should you use getStaticProps?

  • If there is data required to render the page that is available at build time ahead of a user's request.

  • If the data comes from a headless CMS.

  • If the data can be cached publicly and is not user-specific.

  • If the page must be pre-rendered and be very fast, like in the case of SEO.

Incremental Static Regeneration

You can create or update static pages after you have built your site. ISR enables you to use static generation per-page. This means you do not have to rebuild your entire site. ISR gives you the benefit of static while you can scale millions of pages.

Using process.cwd() to read files

Next.js compiles your code into a separate directory, which means you can not use __dirname since this will not return the correct path.

You can use process.cwd() instead, since this gives you the directory where Next.js is actually being executed.

Technical Details to keep in mind

  • getStaticProps runs on build time only. This means it will not receive data that is only available outside of the build time, like during the request time.

  • Things like query parameters or HTTP headers are not available.

  • Since getStaticProps only runs on the server-side, it can not be run on the client-side.

  • getStaticProps is not included in the JS bundle for the browser.

  • You can write direct database queries in your code without them getting sent to the browser.

    • If you do this, make sure you do not fetch an API route from getStaticProps, but write it directly in to the code of getStaticProps.

  • Not only the HTML file gets generated when writing with getStaticProps, there is a JSON file that holds the result of running getStaticProps.

  • You can only export getStaticProps from a page. The reason is that React needs all required data before the page gets rendered. You will also have to use the export async function part, because just adding getStaticProps as a property of the page component will not work

  • Every time you run next dev, getStaticProps will be called.

Static Generation - getStaticPaths

Like said before, if your page has dynamic routes, and it uses getStaticProps, getStaticPaths will need to define a list of paths that have to be rendered to HTML at build time.

The paths key

return {
  paths: [ 
    { params: { id: '1' } },
    { params: { id: '2' } }
  ],
  fallback: ...
}

This required key determines which paths actually have to be pre-rendered.

  • The above code will statically generate posts/1 and posts/2 at build time.

  • Also, the value of the params will have to match the parameters that are used in the page name:

    • Let's say the page name is pages/posts/[postId]/[commentId]

      • params should contain postId and commentId.

    • If the page name uses a catch-all route like pages/[...slug]

      • params should contain slug.

    • If you use a catch-all route, supply one of the following: null, [], undefined or false to render the root-most route.

      • So if you supply slug: false` for `pages/[[...slug]], Next.js will statically generate the page /.

The fallback key

return {
  paths: [
    { params: { id: '1' } },
    { params: { id: '2' } }
  ],
  fallback: ...
}

This key is also required and must contain a boolean value.

  • fallback: false

    • This will make sure no paths are returned and will result in a 404 page.

    • This can be done when a small number of paths has to be pre-rendered, since these get statically generated during build time.

    • This is also useful if new pages are not added often.

  • fallback: true

    • When this is the case, the behavior of getStaticProps will change:

      • All paths that get returned from getStaticPaths will be rendered to HTML at build time by getStaticProps.

      • If there are paths that are not generated, they will not result in a 404 page, Next.js will serve a fallback version of the page on the first request to that page.

      • Next.js will statically generate the requested path HTML and JSON in the background, and therefore will also run getStaticProps.

      • When the above is finished, the browser receives JSON code for the generated path. This can be used to automatically render the page with the required props. In the eyes of the users, the page will be swapped from a fallback page to a full page.

      • During all of this, Next.js will add this path to a list of pre-rendered pages.

    • Is there a moment when fallback: true is useful?

      • It is useful when you have a really large number of static pages that all depend on data. You can not pre-render all your product pages, since builds would take absolutely forever.

  • fallback: blocking

    • When this is the case, if a new path does not get returned by getStaticPaths will wait until HTML is generated, just like in server side rendering. It will then be cached for future requests so this can only happen once per path.

Technical details to keep in mind

  • Use getStaticPaths together with getStaticProps, this is a must.

  • getStaticPaths only runs at build time on server-side.

  • You can only export getStaticPaths from a page, not from a component.

  • You must use export async function instead of using it as a property of the page component.

  • getStaticPaths will get called on every request in development.

Server-side Rendering - getServerSideProps

You can export the asynchronous function getServerSideProps from a page and Next.js will pre-render this page on each request using the data that gets returned by the function.

Parameters for getServerSideProps

getServerSideProps has one parameter, which is an object that can contain the following keys:

  • params

    • This parameter will contain route parameters, if the page uses dynamic routes.

  • req

    • HTTP Incoming Message object.

    • Default is {}

      • It will parse an incoming request.

    • This parameter also provides built in middleware.

      • The middleware is req.cookies.

      • This is an object containing cookies that are sent by request.

  • res

    • HTTP response object

  • query

    • Object representing the query string.

  • preview

    • If set to true, the page is in preview mode.

    • false means otherwise.

  • previewData

    • Preview data that is set by setPreviewData.

  • resolvedUrl

    • Normalized version of the requested URL.

    • It strips the prefix _next/data.

  • locale

    • Contains active locale.

    • If using Internationalized Routing.

  • locales

    • Contains all supported locales.

    • If using Internationalized Routing

  • defaultLocale

    • Contains the configured default locale

    • If using Internationalized Routing

Returns for getServerSideProps

  • props

    • Optional

    • Object with the props that will be received by the page component

    • Should be either a serializable object or a promise that resolves to a serializable object

  • notFound

    • Optional

    • Boolean value

    • Allows the page to return a 404 status and page.

  • redirect

    • Optional

    • Redirect value to allow redirecting to internal or external resources.

When should you use getServerSideProps?

Only if you have to pre-render a page that has data that must be fetched at request time.

Technical details to keep in mind

  • getServerSideProps only runs on the server-side. This means a few things:

    • If you request the page directly, getServerSideProps runs at request time, the page will be pre-rendered with the returned props.

    • If you request this page on client-side page transitions like next/link or next/router, an API request gets sent to the server, which will then run getServerSideProps. It will return a JSON that contains the result of getServerSideProps.

    • getServerSideProps is only allowed to be used as a function and in a page

Fetching data on the client side

If you have to frequently update data, you should not pre-render your data. You can instead fetch your data on the client side.

How does client side fetching work?

First it will immediately show the page without data. You can pre-render some parts of the page with static generation, but you can also show loading states for missing data.

After that, you can fetch the data on the client side and it will display when it is ready.

React Hook: SWR

Next.js created a React hook for data fetching which is named SWR. It is recommended to use this when fetching data on the client side, since it will handle the following aspects:

  • Caching

  • Revalidation

  • Focus tracking

  • Refetching on interval

  • and more

Example code:

import useSWR from 'swr'

const fetcher = (url) => {
  fetch(url).then((res) => {
    res.json())
  }
}

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)
  if (error) {
    return <div>failed to load</div>
  }
  if (!data) {
    return <div>loading..</div>
  }
  return <div>hello {data.name}!</div>}
}

External sources

Next.js documentation about pages

Next.js documentation about data fetching

Images come from Next.js learn

Official website of SWR