Data fetching in Next.js with getServerSideProps and getStaticProps
Tags: nextjs, webdev
Published: 2023-09-12 18:15:31

**Written by [Yomi Eluwande](https://blog.logrocket.com/author/yeluwande/)✏️**

In Next.js, data fetching methods play a crucial role in enabling server-side rendering (SSR), static site generation (SSG), and client-side data fetching for your React components. These methods allow you to fetch data from various sources (e.g., APIs, databases, external services) and use that data to pre-render pages or hydrate them on the client side. 

In this article, we’ll explore the `getInitialProps`, `getServerSideProps`, and `getStaticProps` data fetching methods. We’ll take a look at the role `getInitialProps` played in previous versions of Next.js and the transition to newer and better data fetching methods. 

_Jump ahead_:

*   [Understanding `getInitialProps`](#understanding-getinitialprops)
*   [Transitioning to `getServerSideProps` and `getStaticProps`](#transitioning-getserversideprops-getstaticprops)
*   [A deep dive into the `getServerSideProps` lifecycle](#deep-dive-getserversideprops-lifecycle)
*   [The role of `getInitialProps` in Next.js 13](#role-getinitialprops-next-js-13)
*   [Optimizing `getServerSideProps` for performance in Next.js 13](#optimizing-getserversideprops-performance-next-js-13)
*   [Migrating from `getInitialProps` to `getServerSideProps` or `getStaticProps`](#migrating-getinitialprops-getserversideprops-getstaticprops)

## Understanding `getInitialProps` <a name="understanding-getinitialprops">

`getInitialProps` is a method used in older versions of Next.js (versions prior to 9.3) to fetch data on the server side before rendering a page. It was the primary data fetching method used in Next.js before newer data fetching methods like [`getServerSideProps`](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props) and [`getStaticProps`](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props) were introduced. 

In older versions of Next.js, `getInitialProps` was the primary data fetching mechanism for both SSR and client-side rendering. It allowed developers to perform custom data fetching logic for each page and pass the fetched data as props to the page component:

```javascript
// In older versions of Next.js, you would define getInitialProps like this:

import React from 'react';

const HomePage = ({ posts }) => {
  // Render the list of posts
  return (
    <div>
      <h1>Latest Blog Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
};

HomePage.getInitialProps = async () => {
  // Fetch data from an API
  const response = await fetch('https://api.example.com/posts');
  const posts = await response.json();

  // Return the data as props
  return { posts };
};

export default HomePage;
```

In this example, the `getInitialProps` method fetches the list of blog posts from the API server-side. When a user visits the homepage, the server will pre-render the page with the fetched data and serve it as a complete HTML page. This approach helps with SEO, improves initial page load times, and ensures that the page has the necessary data before being served to the client.

## Transitioning to `getServerSideProps` and `getStaticProps` <a name="transitioning-getserversideprops-getstaticprops">

The transition from `getInitialProps` to `getServerSideProps` and `getStaticProps` in Next.js represented a significant improvement in data fetching and rendering strategies. This change was introduced to simplify data fetching, enhance performance, and provide better predictability in terms of when and where data is fetched. 

Let’s start by looking at what the `getServerSideProps` and `getStaticProps` lifecycles are useful for, and how they each mark pages for rendering. 

`getServerSideProps` is a data fetching method that was introduced in Next.js 9.3\. It is used specifically for server-side rendering (SSR). Unlike `getInitialProps`, `getServerSideProps` is only executed on the server side during the initial page request and not on subsequent client-side navigations. This change improves performance by reducing duplicate data fetching and provides better predictability of server-side data fetching. 

`getStaticProps` is another data fetching method that was introduced in Next.js 9.3, and it is used for static site generation (SSG). When using `getStaticProps`, Next.js pre-renders the page at build time and fetches the data during the build process. The pre-rendered HTML pages are then served to users directly from the CDN, offering faster page loads and reducing server load. 

These new data fetching methods ensured better performance by reducing unnecessary data fetching and improving the performance of your Next.js application by fetching data more intelligently. With `getServerSideProps`, you know that data is fetched only during the initial server-side request, making it easier to understand when and where data is retrieved, and with `getStaticProps`, the data will only be fetched at build time. 

With the introduction of `getStaticProps` and `getServerSideProps`, Next.js users now have two different data fetching methods that are used to mark pages for rendering either at build time or upon each request respectively. 

When a user requests a page that uses `getServerSideProps`, the server will execute this function, fetch the data, and pass it as props to the page component. The page is then rendered on the server with the fetched data and sent to the client as a complete HTML page. This approach is known as [server-side rendering](https://blog.logrocket.com/improve-app-performance-react-server-side-rendering/) (SSR), and it ensures that the page always has the most up-to-date data when accessed by users. 

With `getStaticProps`, you get the option to pre-render pages at build time, generating static HTML files with the fetched data. When you use `getStaticProps`, Next.js runs the function during the build process (not on each request) and fetches the data needed for the page. The fetched data is then used to pre-render the page into a static HTML file, which is saved in the build output directory (e.g., the `build` folder). 

Now, when a user visits a page that was pre-rendered with `getStaticProps`, Next.js serves the static HTML page directly from a CDN, improving page load times and reducing server load. This approach is called popularly known as [static site generation](https://blog.logrocket.com/using-static-site-generation-modern-react-frameworks/) (SSG), and it is ideal for pages with content that doesn't change frequently.

## A deep dive into the `getServerSideProps` lifecycle <a name="deep-dive-getserversideprops-lifecycle">

As mentioned above, the `getServerSideProps` lifecycle is used to fetch data on the server side and pre-render the page with the fetched data before sending it to the client. Unlike `getStaticProps`, `getServerSideProps` executes on each request, making it suitable for pages that require dynamic data or data that changes frequently. 

The `getServerSideProps` function takes a context object as a parameter that contains page data such as `params`, `res`, `req`, `query`, etc. Here's a breakdown of how the `getServerSideProps` lifecycle works:

1.  When a user requests a page that uses `getServerSideProps`, the server-side code is executed first
2.  The `getServerSideProps` function is called, and it fetches the necessary data from external APIs, databases, or other sources
3.  The fetched data is then passed as props to the page component
4.  The page is pre-rendered on the server with the fetched data and sent as a complete HTML page to the client
5.  The client-side JavaScript takes over once the page is loaded, and any subsequent interactions are handled on the client side

When compared to the `getInitialProps` lifecycle, `getServerSideProps` is much cleaner and more predictable in terms of fetching data, especially when it comes to context switching between server operations and client operations. 

With `getInitialProps`, operations were being executed on both the server and client side, which sometimes led to duplicate data fetching during client-side navigation. But with `getServerSideProps`, there was a clear understanding that data fetching logic in the `getServerSideProps` lifecycle would be executed only on the server side during the initial request, eliminating the duplicate data fetching that might occur with `getInitialProps`. 

**Example use cases for `getServerSideProps`:**

*   **Real-time data**: If your page requires real-time data that changes frequently (e.g., live chat messages, real-time analytics), you can use `getServerSideProps` to fetch the latest data on each request
*   **Authenticated data**: When dealing with authenticated data that is user-specific and changes based on the user's session or permissions, `getServerSideProps` is well-suited for fetching this data securely on the server side
*   **Dynamic pages**: For pages with dynamic routes, where the content depends on the route parameters, `getServerSideProps` can fetch the data for the specific route during each request

In summary, `getServerSideProps` offers a more straightforward and efficient way to fetch data on the server side, especially for pages that require server-side rendering and frequently changing data. It provides better control over data fetching, improved performance, and a smoother transition from the `getInitialProps` lifecycle.

## The role of `getInitialProps` in Next.js 13 <a name="role-getinitialprops-next-js-13">

Despite the transition to newer data fetching methods, Next.js has maintained support for `getInitialProps` for backward compatibility. This is because there might be existing projects that rely on `getInitialProps` and transitioning all of them to the newer methods might be impractical in some cases. 

To handle edge cases where `getInitialProps` might still be necessary, consider the following scenarios:

*   **Complex data fetching logic**: If your data fetching logic is complex and can't be easily achieved with `getStaticProps` or `getServerSideProps`, you might continue using `getInitialProps`
*   **Custom SSR logic**: If you need custom server-side rendering logic that can't be achieved with the newer methods, you might choose to use `getInitialProps`
*   **Legacy projects**: If you're working on a legacy project that was built using older versions of Next.js and heavily relies on `getInitialProps`, it might be more practical to continue using it rather than rewriting everything

## Optimizing `getServerSideProps` for performance in Next.js 13 <a name="optimizing-getserversideprops-performance-next-js-13">

`getServerSideProps` runs on every request, which means that if you're doing a lot of data fetching or computations, it can slow down your site. There are a few things you can do to optimize the use of `getServerSideProps` for performance in Next.js 13. 

One is to make sure you're returning the required `props` object with the `props` property, which can help reduce the number of repetitive calls. When you call `getServerSideProps`, Next.js creates a server-side request to fetch the data. This request can be quite expensive, especially if you're doing a lot of computations. If you return the required `props` object, Next.js will memoize the request and reuse the result for subsequent calls. This is important because it means that Next.js doesn't have to make multiple requests to the server to get the same data, which can significantly improve performance. 

Another way to optimize the use of `getServerSideProps` in your project is by taking advantage of smarter caching. It works by caching the results of your request based on the content that was requested. For example, if a user requests a specific page, Next.js will only cache the data for that page. This means that if another user requests a different page, it won't have to load the entire site from scratch, which can save a lot of time. This is different from traditional caching, which simply stores the entire site in a cache and serves it to all users. 

Another benefit of smarter caching is that it allows for "incremental updates". This means that if you make a small change to your code, only the affected parts of the site will be updated in the cache.

## Migrating from `getInitialProps` to `getServerSideProps` or `getStaticProps` <a name="migrating-getinitialprops-getserversideprops-getstaticprops">

Migrating from `getInitialProps` to `getServerSideProps` or `getStaticProps` involves updating your data fetching logic to the new data fetching methods introduced in Next.js. The migration process depends on whether you want to achieve server-side rendering (SSR) or static site generation (SSG). Here's a detailed overview of the steps involved in the migration: 

**Migrating to `getServerSideProps` (SSR):**

1.  **Remove** `getInitialProps`: If your page components use `getInitialProps`, you need to remove it from those components
2.  **Replace** `getInitialProps` **with** `getServerSideProps`: Replace the `getInitialProps` method with the `getServerSideProps` method in your page components. The structure of `getServerSideProps` is different from `getInitialProps`, and it returns an object with the `props` key containing the fetched data
3.  **Pass props to the component**: With `getServerSideProps`, the fetched data will be automatically passed as props to the page component. You can access this data using the `props` parameter of your page component

Let's consider a simple example where you have a blog application, and you want to fetch a list of blog posts from an external API to display on the homepage:

```javascript
// Before migrating from getInitialProps

const HomePage = ({ posts }) => {
  // Render the list of posts
};

HomePage.getInitialProps = async () => {
  // Fetch data from an API
  const response = await fetch('https://api.example.com/posts');
  const posts = await response.json();

  // Return the data as props
  return { posts };
};

// After migrating to getServerSideProps

const HomePage = ({ posts }) => {
  // Render the list of posts
};

export async function getServerSideProps() {
  // Fetch data from an API
  const response = await fetch('https://api.example.com/posts');
  const posts = await response.json();

  // Return the data as props
  return {
    props: { posts },
  };
}
```

**Migrating to `getStaticProps` (SSG):**

1.  **Remove** `getInitialProps`: If your page components use `getInitialProps`, you need to remove it from those components
2.  **Replace** `getInitialProps` **with** `getStaticProps`: Replace the `getInitialProps` method with the `getStaticProps` method in your page components. Like `getServerSideProps`, the structure of `getStaticProps` is different from `getInitialProps`, and it returns an object with the `props` key containing the fetched data
3.  **Data revalidation (optional)**: With `getStaticProps`, you can also include the `revalidate` option in the returned object to specify how often the data should be revalidated and regenerated. This is useful when you want to update the data periodically without redeploying your application

Using the same example use case as above, here is our code before and after migrating from `getInitialProps` and `getStaticProps`:

```javascript
// Before migrating from getInitialProps

const HomePage = ({ posts }) => {
  // Render the list of posts
};

HomePage.getInitialProps = async () => {
  // Fetch data from an API
  const response = await fetch('https://api.example.com/posts');
  const posts = await response.json();

  // Return the data as props
  return { posts };
};

// After migrating to getStaticProps

const HomePage = ({ posts }) => {
  // Render the list of posts
};

export async function getStaticProps() {
  // Fetch data from an API
  const response = await fetch('https://api.example.com/posts');
  const posts = await response.json();

  // Return the data as props
  return {
    props: { posts },
  };
}
```

## Conclusion

In summary, migrating from `getInitialProps` to `getServerSideProps` or `getStaticProps` involves updating the data fetching logic and method signatures to improve performance, predictability, and context switching in your Next.js application. Depending on your use case, you can choose between `getServerSideProps` for server-side rendering or `getStaticProps` for static site generation.

---

## [LogRocket](https://lp.logrocket.com/blg/nextjs-signup): Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, [try LogRocket](https://lp.logrocket.com/blg/nextjs-signup).

[![LogRocket Signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://lp.logrocket.com/blg/nextjs-signup)

[LogRocket](https://lp.logrocket.com/blg/nextjs-signup) is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your Next.js apps — [start monitoring for free](https://lp.logrocket.com/blg/nextjs-signup).