# Mastering Data Fetching in Next.js Next.js is a robust React framework that excels in [server-side rendering](https:nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering) (SSR) and [static-site generation](https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation) (SSG). This consequently makes it ideal for improving search engine optimization (SEO) and performance, especially for single-page applications (SPAs). To achieve these benefits, Next.js ships with various data-fetching methods including `getServerSideProps`, `getStaticProps`, `getStaticPaths`, and libraries like `useSWR` to fetch data from databases, APIs, and hydrate pages with the data. In this article, we'll explore these data-fetching methods and assess their ideal use cases and best implementation practices.This will help you decide which data fetching method is ideal for your next project. ## Understanding Next.js Data Fetching Methods Before we can delve into the data fetching methods, it would help if we briefly looked into Next's rendering methods. Essentially, with SSR the rendering is done on the server side at the request time/run time. As such for every request made, the server fetches the data and the HTML content and then sends it to the client. SSG, on the other hand, does the rendering at build time, instead of at every request. This way the HTML can be cached by a [CDN ](https://www.cloudflare.com/en-gb/learning/cdn/what-is-a-cdn/)and consequently be reused on each request. Ultimately, in both SSR and SSG, the content is readily available for indexing by search engine crawlers, leading to improved visibility in the search results. While the improved performance and SEO benefits come inherently with Next.js, the key to fully unlocking them lies in knowing when to implement the framework's data fetching methods. ### 1. Server-side Data Fetching with getServerSideProps `getServerSideProps` is an asynchronous function for fetching data on the server side and pre-rendering the page with the data before sending it to the client. The function runs at request time making, it is particularly useful for sites with dynamic data for example; live chat, fetching the latest data analytics, geolocation, and retrieving authenticated data whose permissions change based on the user's permissions and session. Usually, when a page with `getServerSideProps` is requested the server calls the function fetches the necessary data in `JSON` format, and passes it as props to the page component. The page is then pre-rendered with the data and sent as an HTML page to the client side. Generally, the syntax looks like this: ``` javascript //This gets called on every request export async function getServerSideProps(context) { // Fetch data from an API const res = await fetch( `https://api.polygon.io/v2/aggs/ticker/AAPL/range/1/day/2023-01-09/2023-01-09?adjusted=true&sort=asc&limit=120&apiKey=*`, ); const data = await res.json(); // Pass the fetched data as props return { props: { data, }, }; } function MyPage({ data }) { // Render the page with the fetched data return ( <div> <h1>Server-Side Data Fetching</h1> <p>{data.c}</p> <p>{data.h}</p> </div> ); } export default MyPage; ``` In code above, the `getServerSideprops` async function fetches the stock data from an endpoint on every request. The data is then returned as props which consequently is passed to the page component for rendering where users can see the stock's closing and highest prices for the day. ### 2. Static Data Fetching with getStaticProps `getStaticProps` is also an asynchronous function exported from a page component. However, unlike `getServerSideProps` it's used for static site generation (SSG), and as such it pre-renders a page at build time using the props returned from its data fetching logic. This makes `getStaticProps` more suitable for pages with content that doesn't change frequently for example product listings, blog posts, and marketing pages. By default, Next.js pre-renders pages using SSG whereby the HTML file for each page is generated when `next build` is initialized in production. However, if the content of your page depends on an external data source, say a headless [content management system](https://aws.amazon.com/what-is/headless-cms/) (CMS), you should use `getStaticProps` on your page. This ensures that the content will be available ahead of a user's request, improving SEO and performance. ```javascript export async function getStaticProps() { // Fetch products posts from an API const res = await fetch(`https://fakestoreapi.com/products`); const posts = await res.json(); // the Productlisting component // will receive `products` as a prop at build time return { props: { products, }, }; } // products will be populated at build time by getStaticProps() function Productlisting({ products }) { // Render the page with the fetched data return ( <div> <h1>Static Data Fetching</h1> <p>{product.title}</p> <p>{product.price}</p> </div> ); } export default Productlisting; ``` In the example above, the `getStaticProps` fetches the list of products and returns them as props. The props are then passed to the ProductListing component where products details such as price and product title are rendered - all these functions are run at build time. ### 3. Dynamic Routes with getStaticPaths Similar to `getStaticProps`, `getStaticPaths` is used for SSG, the only difference is that the latter is used as a complementary data fetching method for pages with dynamic routing. Think of a page where its paths depend on an external data source, for example `products/product/[id] `. In such a case, you want to pre-render the path at build time so that it's readily available ahead of a user's request. Let's look at an example of dynamic paths that depend on data fetched from an endpoint: ```javascript // This component will render details of a single product export default function Product({ product }) { return ( <div> <h1>{product.title}</h1> <p>{product.description}</p> </div> ); } export async function getStaticPaths() { // Fetch all product IDs const res = await fetch("https://fakestoreapi.com/products"); const products = await res.json(); // Generate paths for each product const paths = products.map((product) => ({ params: { id: product.id.toString() }, // Convert id to string })); // Return paths and fallback value return { paths, fallback: false, }; } export async function getStaticProps({ params }) { // Fetch data for a specific product based on its ID const res = await fetch(`https://fakestoreapi.com/products/${params.id}`); const product = await res.json(); // Return the product data as props return { props: { product, }, }; } ``` First, Next.js runs `getStaticPaths` function to determine all available paths/product ids for the all products. The paths are then stored in array which is then mapped, with each product's id corresponding to a specific path. These paths are used for pre-rendering the product data by the `getStaticProps` function which takes in a parameter object containing the product's id. The `fallback` keyword accepts three values; `false`, `true` or `blocking`. When it's set to `false`, Next.js will only pre-render the paths specified in the `paths` array, any other path will result in a 404 error. If it's set to `true`, the requested page will be generated dynamically on the server for the first time it's requested and then cached for future requests. If a request is made to a path that hasn't been cached yet, Next.js returns a static HTML page that had been created at build time. This is where you're expected to show the user that the page is loading. This is useful especially when you have a large number of dynamic routes where it doesn't sense to pre-render all of them at build time. As for fallback `blocking`, it's pretty similar to `true` the only difference is that it doesn't return a loading page, instead it only returns a fully generated page, meaning there's no client-side loading. However, just like fallback `true`, the page is cached for future requests. ### 4. Client-side Data Fetching with useSWR In some cases, you may need to use [client-side rendering](https://nextjs.org/docs/pages/building-your-application/rendering/client-side-rendering) (CSR) for fetching data based on a user's interaction or other factors that can't be determined at build time. It's also makes sense to use CSR for data that changes frequently for example live feeds and real-time notifications. However, it's important to note that client-side data fetching can slow down the performance of your application and impact the SEO. This is because the data is fetched when the component or page mounts. For client-side data fetching, Next.js recommends using the [`useSWR` ](https://swr.vercel.app/docs/with-nextjs)React hook library. It offers caching, re-validation, focus tracking, and re-fetching on interval features. Consider the example below for fetching user's data ```javascript "use client"; import useSWR from "swr"; function MyComponent() { const { data, error } = useSWR("/api/data", fetcher); if (error) return <div>Error fetching data</div>; if (!data) return <div>Loading...</div>; return <div>{data.name}</div>; } export default MyComponent; ``` To use the hook, you need to first import it from the `swr` library then invoke it inside the component function. The hook takes two parameters, the url endpoint to fetch data from and the fetcher, which is an asynchronous function responsible for fetching the data.The hook then returns an object with `data` and `error` properties, representing the data fetched and potential errors encountered in the process. ## Data Fetching Best Practices Having looked at Next's data-fetching methods, lets delve into some of the best practices optimizing data fetching performance: * caching Implementing effective caching strategies helps improve the overall performance and loading speed of your application. You can use browser caching, server-side caching and CDN caching. * streaming Streaming helps improve scalability and reduce latency by allowing you to fetch data in small incremental chunks rather than waiting for the entire dataset to be available. As such, you can instantly render parts of a page that don't require data and show loading state on parts that are waiting on the data to be fetched. ## Combining Client-side and Server-side Data Fetching Methods You can combine both client-side and server-side data fetching methods to enjoy the benefits of both worlds. But first, you need to identity which data is essential for initial page render and should be included in the SSR process. Usually, you'd want to include content necessary for SEO and page navigation in the SSR data fetching. You can then fetch non-critical content on the client-side for immediate user interaction as the rest of the data is being fetched. ## Conclusion Overall, each Next.js data fetching method has its own unique benefits which makes it suitable for different use cases. There's isn't on that's better than the other. Whether you decide to use SSG or SSR ultimately depends on your they type of application and data you're dealing with. A general rule of thumb is to SSR for dynamic data and SSG for data that doesn't change frequently. You can also implement hybrid rendering to optimize performance and user experience.