Comprehensive Guide to Data Fetching in Next.js
Comparing fetch, axios, and SWR for optimal performance
Start typing to search...
In the world of web development, fetching data efficiently is crucial for building responsive, user-friendly applications. In Next.js, there are multiple ways to fetch data, each with its own set of advantages and drawbacks. In this guide, we’ll dive deep into three popular methods: fetch, axios, and SWR, discussing when and how to use each, along with their pros, cons, and best practices.
The fetch API is a native JavaScript function that provides a way to make HTTP requests. It’s a low-level API with a minimalistic design, making it a great choice for straightforward tasks.
fetch returns a Response object, and you need to call .json() to parse the response body into a JavaScript object.fetch only rejects the promise if there’s a network error. HTTP errors (like 404 or 500) don’t automatically reject the promise, so you must manually check response.ok.fetch for Server-Side Data Fetching: Since fetch is a native API, it's a good choice for server-side operations, especially in API routes or within getServerSideProps or getStaticProps.response.ok: Always check response.ok to handle HTTP errors properly.fetch doesn't have built-in features like automatic retries or interceptors, consider these limitations for highly complex requests.import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const apiKey = process.env.SECURE_API_KEY; // Use environment variable for sensitive data
  try {
    const response = await fetch("https://reqres.in/api/users?page=2", {
      headers: {
        Authorization: `Bearer ${apiKey}`,
      },
    });
    if (!response.ok) {
      throw new Error(`Failed to fetch data: ${response.statusText}`);
    }
    const data = await response.json();
    res.status(200).json(data);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
}
axios is a popular third-party HTTP client library that simplifies the process of making HTTP requests. It offers additional features and a more intuitive API compared to fetch.
axios automatically parses JSON responses, so you don't need to call .json().axios automatically rejects the promise for HTTP errors (non-2xx responses), simplifying error handling.axios supports request and response interceptors, allowing you to modify requests or responses globally.axios library, adding to your project's bundle size.axios introduces additional overhead compared to the native fetch API.axios for Client-Side and Server-Side Requests: Its simplicity and features make axios a good choice for both front-end and back-end data fetching.axios's automatic rejection of non-2xx responses to reduce the need for manual error checks.import { useEffect, useState } from "react";
import axios from "axios";
interface Resource {
  id: number;
  name: string;
  year: number;
  color: string;
  pantone_value: string;
}
const AxiosExample = () => {
  const [data, setData] = useState<Resource[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get("https://reqres.in/api/unknown");
        setData(response.data.data);
      } catch (err) {
        setError((err as Error).message);
      } finally {
        setLoading(false);
      }
    };
    fetchData();
  }, []);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;
  return (
    <div>
      <h1>Axios Example</h1>
      <ul>
        {data.map((resource) => (
          <li key={resource.id} style={{ backgroundColor: resource.color }}>
            {resource.name} ({resource.year}) - Pantone:{" "}
            {resource.pantone_value}
          </li>
        ))}
      </ul>
    </div>
  );
};
export default AxiosExample;
SWR (stale-while-revalidate) is a React hook library for data fetching developed by Vercel, the team behind Next.js. It’s designed for client-side data fetching with caching and revalidation features.
SWR automatically caches the data from API requests and reuses the cache on subsequent renders or requests.SWR simplifies implementing pagination and infinite loading, which can be complex with fetch or axios.SWR can automatically retry failed requests, reducing the need for custom retry logic.SWR is designed to run on the client side, so it’s not suitable for server-side rendering scenarios where you need data before rendering the page.axios, SWR is a third-party library, adding to your project's dependencies.SWR for Client-Side Fetching: Perfect for front-end scenarios where you need features like caching, revalidation, and optimistic updates.SWR excels in scenarios with frequently changing or user-specific data.SWR in conjunction with Next.js API routes for secure and efficient data fetching.import Image from "next/image";
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
const SecureFetchExample = () => {
  const { data, error, isLoading } = useSWR("/api/secure-data", fetcher);
  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return (
    <div>
      <h1>Secure Fetch Example with SWR</h1>
      <ul>
        {data.data.map((resource: any) => (
          <li key={resource.id}>
            <Image
              src={resource.avatar}
              width={50}
              height={50}
              alt={resource.first_name}
            />
            {resource.email} ({resource.id}) - Pantone: {resource.pantone_value}
          </li>
        ))}
      </ul>
    </div>
  );
};
export default SecureFetchExample;
fetch: Use for secure API calls in API routes or when fetching dynamic data that needs to be up-to-date on every request (getServerSideProps).axios: Ideal for more complex API calls with easier configuration and automatic error handling, used in both getServerSideProps and getStaticProps.SWR: Best for fetching data on the front end with caching, revalidation, and real-time updates. Ideal for user-specific or frequently changing data.getServerSideProps for Dynamic Content: Fetch data on each request for content that needs to be up-to-date.getStaticProps for Static Content: Ideal for content that doesn't change often, improving performance with static generation.fetch to keep sensitive data like API keys secure.SWR for Dynamic or User-Specific Data: Use SWR to handle client-side data that needs to be revalidated or cached.SWR for scenarios where the data changes frequently and you need to keep the UI updated.Understanding when to use fetch, axios, and SWR in your Next.js applications can significantly enhance both the performance and user experience of your projects. By following the best practices outlined in this guide, you can ensure that your data fetching strategy is secure, efficient, and perfectly suited to your application's needs.