Understanding Next.js Data Fetching (CSR, SSR, SSG, ISR)
Introduction
When I started to learn Next.js, I got overwhelmed with the list of abbreviations that looks similar, I didn't know what it is and what is the difference. It is quite confusing because when using Create React App, we usually only use 1 strategy to fetch data from API which is using useEffect
.
Next.js has many data fetching strategies. Although initially Next.js was well known to be a Server-Side Rendering Framework, it turns out that Next.js has 4 methods of Data Fetching. Here is the short explanation each so you get familiar with the abbreviation of CSR, SSR, SSG, ISR.
- CSR - Client-Side Rendering, this is the usual kind of data fetching 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 API 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, this is a new thing, shortly put, 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 didn't get that, because I will be explaining it thoroughly, just familiarize the words first.
I mentioned before that there is a special function that will run when using a specific data fetching method. Keep that in mind as I will show you what is that special function.
This code example will fetch a date-time from an API using axios, then render it on the page. It is useful to see the date-time so we can truly know when the API is hit.
Client-Side Rendering (CSR)
Special Function: useEffect
Code Example
export default function CSRPage() {
const [dateTime, setDateTime] = React.useState<string>();
React.useEffect(() => {
axios
.get('https://worldtimeapi.org/api/ip')
.then((res) => {
setDateTime(res.data.datetime);
})
.catch((error) => console.error(error));
}, []);
return (
<main>
<TimeSection dateTime={dateTime} />
</main>
);
}
Demo
Terms:
- PT → Preview Time, the time shown when the API is hit. Can be seen in the middle.
- RT → Real-Time, the real ticking time updating every second, can be seen on the right bottom corner
Video Description:
- Page reloads on 15:46:03 Real-Time (RT), then a LOADING indicator is shown
- After about 1s, Preview Time is showing 15:46:04(PT)
Keys to Emphasize
- useEffect function, this function is the key indicator that a page is using Client-Side Rendering.
- LOADING indicator, because the data fetching runs after the page is rendered, the data is not fetched instantly, therefore showing a loading state.
- Data is fetched on every page request, which is why the time shown is different for each reloads.
Server Side Rendering (SSR)
Special Function: getServerSideProps
Code Example
export default function SSRPage({ dateTime }: SSRPageProps) {
return (
<main>
<TimeSection dateTime={dateTime} />
</main>
);
}
export const getServerSideProps: GetServerSideProps = async () => {
const res = await axios.get('https://worldtimeapi.org/api/ip');
return {
props: { dateTime: res.data.datetime },
};
};
Demo
Video Description:
- Clicked the link on 16:02:38(RT), a slight pause for 2s, then page loads showing 16:02:40(PT)
Keys to Emphasize
- getServerSideProps function, this function is the key indicator that a page is using Server-Side Rendering.
- DELAY before render, and no LOADING indicator, the data is fetched before the page is rendered, so there will be a slight delay where the API is being hit at the moment, then it will show the page without loading indicator
- Data is fetched on every page request, which is why the time shown is different for each reloads.
CSR vs SSR
Here is the difference between CSR vs SSR, keep an eye on delay and loading indicators.
Video Description:
- When clicking CSR, with no delay a LOADING text is visible for a second, then the Preview Time loads.
- When clicking SSR, a slight delay happened, then the page loads.
Keys to Emphasize
- CSR hit the API after the page loads.
- SSR hit the API before the page loads.
Short addition
I will probably create a new post about the pros and cons of each method, but when using CSR the SEO is not really great because the data is only fetched after the page renders. This is useful and convenient when we are creating a page with a gated authentication, as you don't really need SEO for pages like the dashboard, edit profile page, etc.
But, for the SSR, although it creates a delay, data that was fetched is injected and helps SEO. This is quite useful for a thread or post that we need to get traffic into, like Reddit or some sort.
Static Site Generation (SSG)
Special function: getStaticProps
Code Example
export default function SSGPage({ dateTime }: SSGPageProps) {
return (
<main>
<TimeSection dateTime={dateTime} />
</main>
);
}
export const getStaticProps: GetStaticProps = async () => {
const res = await axios.get('https://worldtimeapi.org/api/ip');
return {
props: { dateTime: res.data.datetime },
};
};
Demo
Video Description:
- Preview Time is showing 13:39:36(PT). But the real-time is 16:16:59(RT), about 3 hours late.
- Reloading and going back and forth to the home page did not change anything.
Keys to Emphasize
- getStaticProps function, this function is the key indicator that a page is using Static Site Generation.
- Fetched when running
yarn build
, the API will be hit ONLY when the application is building. This is why the time is at 13:39, while the real-time is 16:17. - Data will not change because no further fetch, which is why the time shown is the same for each reloads.
Incremental Static Regeneration
Special function: getStaticProps
+ revalidate
Code Example
export default function ISR20Page({ dateTime }: ISR20PageProps) {
return (
<main>
<TimeSection dateTime={dateTime} />
</main>
);
}
export const getStaticProps: GetStaticProps = async () => {
const res = await axios.get('https://worldtimeapi.org/api/ip');
return {
props: { dateTime: res.data.datetime },
revalidate: 20,
};
};
Demo
Disclaimer: Revalidate time is set to 20 seconds.
Video Description:
- At first, it was 16:40:12(PT), and real-time when reloading is 16:40:25(RT) and 16:40:29(RT). In those 2 reload, Preview Time (PT) did not change.
- Then, when 16:40:32(RT) (20s after initial), reload is done twice, the first time on 16:40:36(RT) and 16:40:40(RT). The Preview Time change to 16:40:37(PT) after the second reload.
Keys to Emphasize
Now, this is might be confusing for you, but here is the key I want you to look at.
- When in a 20-second cooldown span–16:40:12(RT) - 16:40:32(RT), reloading doesn't trigger changes. This is because the page is in a cooldown state, as we set on the
revalidate
key. - After the 20-second cooldown–16:40:32(RT), we did 2 reloads.
- First Reload at 16:40:36(RT), we know that it is not on the cooldown state anymore. The first visit after the cooldown state is off, is going to trigger page rebuild. Page rebuild meaning, only this certain page is going to be rebuild. Not the whole application. The fetch API will run in the background, but there will be no changes on the Preview Time
- Second Full Reload at 16:40:40(RT), the Preview Time change to 16:40:37(PT). Exactly a second after the page rebuild (which means the rebuild takes about 1s). This second reload is going to serve that rebuilt page from the previous reload.
Revisiting Page vs Full Reload
Terms:
- Revisiting pages → navigating using next/link (going back to home, then to that page again)
- Full reload → doing reload at a website (command+r)
Video Description:
- Revisiting pages at the first time 18:38:45(RT), will trigger rebuild, but after the second revisit, the Preview Time did not change.
- After a full reload, then Preview Time is changed to 18:38:45(PT)
Note:
- The first reload does not have to be a full reload, we can go back to the home page, then to that page again (revisit), it will trigger the rebuild as long as we are not in the cooldown state.
- But, the second reload must be a full reload. Going back to the home page, then to the page again won't change the new Preview Time.
Now, this is a case where we are assuming that only 1 person is accessing the website. But, that reloads will happen every person visit while still respecting the cooldown state.
Is it going to be rebuilt every 20s then?
Nope.
When the cooldown is off, if no one visits the page, then that page will not rebuild, even after long past the 20s.
But, the first person that visits when the cooldown state is off, is going to trigger a rebuild. That person won't be seeing changes. But, the changes will be served for the next full reload.
Conclusion
That's all, folks!
If you have understood this material, I suggest you to read more about How to choose between them. I provide 4 metrics for you to consider and some example!