How Axios Handles SSR in Next.js and Nuxt

This article explains how the Axios HTTP client operates within Server-Side Rendering (SSR) architectures such as Next.js and Nuxt. It covers how Axios executes seamlessly across client and server environments through its isomorphic design, how to manage context-specific challenges like cookie forwarding and relative URLs, and the best practices for preventing cross-request data leaks on the server.

Isomorphic Execution and Adapters

Axios is an isomorphic (or universal) library, meaning identical code can run in both the browser and a Node.js server. It achieves this using platform-specific adapters:

When a page is rendered on the server in Next.js or Nuxt, Axios automatically switches to its Node.js adapter to fetch data before the final HTML is generated and sent to the client.

Handling SSR in Next.js

In Next.js, SSR data fetching occurs primarily within server-only functions like getServerSideProps (Pages Router) or inside React Server Components and Server Actions (App Router).

Absolute URLs Requirement

Node.js does not have an implicit origin (such as window.location.origin). Because of this, relative endpoints like /api/user will fail during server execution. Requests must use fully qualified absolute URLs (e.g., https://api.example.com/user or http://localhost:3000/api/user).

Forwarding Headers and Authentication

Server-side requests made by Axios do not automatically include browser cookies or user headers. In getServerSideProps, you must manually extract incoming request headers from the context object and assign them to the Axios configuration:

export async function getServerSideProps(context) {
  const { req } = context;
  
  const response = await axios.get('https://api.example.com/profile', {
    headers: {
      cookie: req.headers.cookie || '',
      authorization: req.headers.authorization || '',
    },
  });

  return {
    props: {
      user: response.data,
    },
  };
}

Handling SSR in Nuxt

Nuxt provides built-in mechanisms (such as useAsyncData and the older @nuxtjs/axios module) to coordinate data fetching across both boundaries.

Dynamic Base URLs

Nuxt allows defining different base URLs depending on the execution context. When using Axios in Nuxt, configure a baseURL for client-side requests and a browserBaseURL or server-specific base URL for internal API communication (often targeting internal Docker networks or localhost).

Nuxt SSR Context and Interceptors

In Nuxt, interceptors can attach session data during SSR. By accessing the Nuxt event context (useRequestEvent in Nuxt 3 or the context parameter in Nuxt 2 plugins), Axios can be configured to mirror authentication tokens and cookies:

// Nuxt 3 plugin example
export default defineNuxtPlugin(() => {
  const event = useRequestEvent();
  const api = axios.create({
    baseURL: process.server ? process.env.INTERNAL_API_URL : process.env.PUBLIC_API_URL,
  });

  if (process.server && event) {
    api.defaults.headers.common.cookie = event.node.req.headers.cookie || '';
  }

  return {
    provide: { api },
  };
});

Core SSR Challenges and Solutions

1. Avoiding State and Credential Leaks

In a client-only single-page application, a single global Axios instance works well. In SSR, the Node.js server serves multiple users concurrently. Storing user-specific credentials (like tokens or cookies) on a shared, global Axios instance creates a critical security vulnerability where one user's session data can leak to another user.

Solution: Create fresh, request-scoped Axios instances using axios.create() inside server lifecycle hooks or plugins for each incoming request.

2. Hydration Mismatches and Duplicate Requests

If data is fetched on the server using Axios, that same data must be passed down to the client as part of the initial state payload (via Next.js props or Nuxt useState/useAsyncData). If the client does not receive the initial state, Axios will execute the request a second time on the client upon page load, resulting in layout flickering or hydration errors.

3. Server-to-Server Network Latency

When rendering on the server, using public domain names can route traffic out through public DNS and load balancers back into the same server infrastructure.

Solution: Configure Axios to use private, internal network addresses (such as http://127.0.0.1:port or internal service names in containerized environments) when process.server or typeof window === 'undefined' evaluates to true.