Skip to content

Understanding Next.js Data Fetching for Beginners

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

When I started to learn Next.Js, I felt a little bit lost with some abbreviations they use to make the data fetching. All of them look pretty simmilar, but they have different meanings. If you feel the same, you are not alone. Let's discover what CSR, SSR, SSG, and ISR means, and how we can use them.

It is quite confusing because I, as an Angular developer, only knew one strategy to fetch the data:HttpClient. But for example, if you are more familiar with React, you probably use a different strategy: useEffect.

So, let's get started. Vercel's Next.js framework has four different data fetching options despite being known as a server-side render framework:

  • CSR - Client-Side Rendering is a common data fetching method using useEffect. It will fetch the data from the API every single page request on the client-side (after the page is rendered, then the function will run).
  • SSR - Server-Side Rendering will run a special function to fetch data from the API with every page request on the server-side (before the page is loaded, that special function will run first, creating a delay, then after that, it will serve the page).
  • SSG - Static Site Generation will run a special function to fetch data once when that page builds.
  • ISR – Incremental Static Regeneration offers a new method. Shortly put, it is a combination of SSG, and SSR, where it served statically, but at a certain time and certain condition, that page will rebuild and fetch the data from the API again.

Don't worry if you don't understand any of the concepts. I will explain a little bit further shortly.

CSR (Client-Side Rendering)

This is a basic example of how you can use Client-Side Rendering. I'm using the well known useEffect method from React.

const ClientSide = () => {
  const [data, setData] = useState(null);
  const [isLoading, setLoading] = useState(false);

  useEffect(() => {
    setLoading(true);
    fetch('api/hello')
      .then((res) => res.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      });
  }, []);

  if (isLoading) return <p>Loading...</p>;
  if (!data) return <p>No profile data</p>;

  return (
    <div>
      <h1>My name is {data.name}</h1>
    </div>
  );
};

export default ClientSide;

You can see how it works on Stackblitz.

We can highlight 2 things here:

  • The useEffect method to make the retrieve of the name every time the page loads.
  • A loading indicator, this is used to wait for the fetching data, because the data is fetched after the page is rendered.

SSR (Server-Side Rendering)

Just to keep in mind, when you are using Server-Side rendering, and using the method getServerSideProps(), Next.js will pre-render this page on each request using the data returned by getServerSideProps.

import styles from '../styles/Home.module.css';

const ServerSide = ({ joke }) => {
  return (
    <div className={styles.container}>
      <span className={styles.description}>Today's joke:</span>
      <h1 className={styles.title}>{joke}</h1>
    </div>
  );
};

// This gets called on every request
export async function getServerSideProps() {
  const url = 'https://icanhazdadjoke.com/';
  const res = await fetch(url, {
    headers: {
      Accept: 'application/json',
    },
  });
  const data = await res.json();

  return {
    props: {
      joke: data.joke,
    },
  };
}

export default ServerSide;

You can see how it works: Stackblitz

We had 3 highlights here:

  • Method getServerSideProps(), is a function indicating that a page is using Server-Side Rendering.
  • We had a delay before render, and NO loading indicator. The data is fetched before the page is rendered, so that's why we can see a little delay.
  • Data is fetched on every request, that's why every time we reload the page, is showing a different dad joke.

SSG (Static Site Generator)

If we take a look at the code below, we will see that it is pretty similar to the SSR code, but the difference here is the getStaticProps method. This method will only fetch when the app is building.

import styles from '../styles/Home.module.css';

const StaticSite = ({ joke }) => {
  console.log(joke);

  return (
    <div className={styles.container}>
      <span className={styles.description}>Today's joke:</span>
      <h1 className={styles.title}>{joke}</h1>
    </div>
  );
};

// This gets called on every request
export async function getStaticProps() {
  console.log('getStaticProps');

  const url = 'https://icanhazdadjoke.com/';
  const res = await fetch(url, {
    headers: {
      Accept: 'application/json',
    },
  });
  const data = await res.json();
  console.log(data);

  return {
    props: {
      joke: data.joke,
    },
  };
}

export default StaticSite;

The highlights here are:

  • getStaticProps is a method indicating that the page is using Static Site Generation.
  • Data will be fetched only when you run yarn build. The API will be hit only when the app is building.
  • Data will NOT change because there is no further fetch.

You can see how it works: Stackblitz

ISR (Incremental Static Regeneration)

This strategy works pretty simmilar like SSG, but here we need to add a revalidate prop to our main getStaticProps function.

import styles from '../styles/Home.module.css';

const IncrementalStatic = ({ joke }) => {
  console.log(joke);

  return (
    <div className={styles.container}>
      <span className={styles.description}>Today's joke:</span>
      <h1 className={styles.title}>{joke}</h1>
    </div>
  );
};

export async function getStaticProps() {
  console.log('getStaticProps');

  const url = 'https://icanhazdadjoke.com/';
  const res = await fetch(url, {
    headers: {
      Accept: 'application/json',
    },
  });
  const data = await res.json();
  console.log(data);

  return {
    props: {
      joke: data.joke,
      revalidate: 20,
    },
  };
}

export default IncrementalStatic;

There are a few keys to highlight here:

  • When you set the revalidate prop to certain amount of time (in our example we set it to 20), reloading doesn't trigger changes. The page will remain in a cooldown state.

  • Is the page rebuilt every 20 seconds then?

No. When the cooldown state is off, if no one visits the page, it will not rebuild even after the 20s pass. But the first person who enters the page when the cooldown state is off will trigger a rebuild. However, that person will not see those changes. But the changes will be applied to the next full reload.

You can see how it works: Stackblitz

Conclusion

Understand how these abbreviations work, and how we can use it in a Next.js app will help us develop more robust solutions, and use Next.js' full potential. I know these terms can sound overwhelming and difficult to understand, but with a little bit of practicing, we can see in action in a few steps.

In future blog posts, we will see the best approach to identify and choose between them.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co