---
title: Usage with Next.js
type: integration
summary: Integrate SWR with Next.js for server-side rendering and static generation.
prerequisites:
  - /docs/getting-started
related:
  - /docs/prefetching
  - /docs/advanced/cache
---

# Usage with Next.js



## App Router

### Server Components

<Callout type="default" emoji="✅">
  In Next.js App Router, all components are React Server Components (RSC) by default. **You can import SWRConfig and the key serialization APIs from SWR in RSC.**
</Callout>

```tsx filename="app/page.tsx" copy
import { unstable_serialize } from 'swr' // ✅ Available in server components
import { unstable_serialize as infinite_unstable_serialize } from 'swr/infinite' // ✅ Available in server components

import { SWRConfig } from 'swr' // ✅ Available in server components
import { preload } from 'swr' // ✅ Available in server components
```

<Callout type="error">
  You could not import hook APIs from SWR since they are not available in RSC.
</Callout>

```tsx filename="app/page.tsx" highlight={1}
import useSWR from 'swr' // ❌ This is not available in server components
import useSWRInfinite from 'swr/infinite' // ❌ This is not available in server components
import usesSWRMutation from 'swr/mutation' // ❌ This is not available in server components
```

### Client Components

You can mark your components with `'use client'` directive or import SWR from client components, both ways will allow you to use the SWR client data fetching hooks.

```tsx filename="app/page.tsx" highlight={1} copy
'use client'

import useSWR from 'swr'

export default function Page() {
  const { data } = useSWR('/api/user', fetcher)
  return <h1>{data.name}</h1>
}
```

### Prefetch Data in Server Components

The recommended approach in React Server Components (RSC) is to start fetching with `preload` and pass the returned data to the client component tree through the `cacheData` option of `<SWRConfig>`:

```tsx filename="app/layout.tsx" copy
import { preload, SWRConfig } from 'swr'

export default async function Layout({ children }: { children: React.ReactNode }) {
  const cacheData = {
    ...preload('/api/user', fetchUserFromAPI),
    ...preload('/api/posts', fetchPostsFromAPI),
  }

  return (
    <SWRConfig value={{ cacheData }}>
      {children}
    </SWRConfig>
  )
}
```

<Callout emoji="💡">
  Both `preload` calls start fetching immediately, so the requests run in parallel without being awaited in the layout.
</Callout>

In React Server Components, the promises inside `cacheData` can cross the `"use client"` boundary, and SWR resolves them automatically during Server-Side Rendering:

```tsx filename="app/page.tsx" copy
'use client'

import useSWR from 'swr'

export default function Page() {
  // SWR resolves the data preloaded by the Server Component.
  // Both `user` and `posts` are ready during SSR and client hydration.
  const { data: user } = useSWR('/api/user', fetcher)
  const { data: posts } = useSWR('/api/posts', fetcher)

  return (
    <div>
      <h1>{user.name}'s Posts</h1>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}
```

SWR uses the server-loaded result for the initial render. On the client, it takes over and continues with its usual revalidation behavior.

With `preload` and `cacheData`, fetching starts as early as possible on the server. Only the UI boundaries that consume the data, such as the nearest `Suspense` boundary or Next.js layout, are blocked during streaming SSR.

<Callout type="default">
  To incrementally adopt this prefetch pattern in your application, you can enable the `strictServerPrefetchWarning` option. This will show a warning message in the console when a key has no pre-filled data provided, helping you identify which data fetching calls could benefit from server-side prefetching.
</Callout>

### How `cacheData` Works

<Callout emoji="🧪">
  This feature requires SWR 2.5.0-beta.1 or later and is currently experimental.
</Callout>

In a Server Component, `preload(key, fetcher)` starts the fetch immediately and returns a request-scoped `CacheData` object. Pass that object to the `cacheData` option of `SWRConfig`:

```tsx filename="app/page.tsx" copy
import { preload, SWRConfig } from 'swr'
import { User } from './user'

const getUser = () => fetchUserFromDatabase()

export default function Page() {
  const cacheData = preload('/api/user', getUser)

  return (
    <SWRConfig value={{ cacheData }}>
      <User />
    </SWRConfig>
  )
}
```

The client component uses the same key with its usual client-side fetcher:

```tsx filename="app/user.tsx" copy
'use client'

import useSWR from 'swr'

const fetcher = (url: string) => fetch(url).then(res => res.json())

export function User() {
  const { data } = useSWR('/api/user', fetcher)
  return <h1>{data?.name}</h1>
}
```

SWR uses the server-loaded result for the initial render, writes it to the client cache during hydration, and skips the duplicate initial client request. Later revalidations still use the client-side fetcher.

Each `preload` call returns a new object. Merge the objects to preload multiple keys without awaiting them:

```tsx
const cacheData = {
  ...preload('/api/user', getUser),
  ...preload('/api/posts', getPosts),
}
```

`preload` serializes complex SWR keys automatically. The `cacheData` option is only supported by `SWRConfig`; it cannot be passed directly to `useSWR`.

## Client Side Data Fetching

If your page contains frequently updating data, and you don’t need to pre-render the data, SWR is a perfect fit and no special setup is needed: just import `useSWR` and use the hook inside any components that use the data.

Here’s how it works:

* First, immediately show the page without data. You can show loading states for missing data.
* Then, fetch the data on the client side and display it when ready.

This approach works well for user dashboard pages, for example. Because a dashboard is a private, user-specific page, SEO is not relevant and the page doesn’t need to be pre-rendered. The data is frequently updated, which requires request-time data fetching.

## Pre-rendering with Default Data

If the page must be pre-rendered, Next.js supports [2 forms of pre-rendering](https://nextjs.org/docs/basic-features/data-fetching):
**Static Generation (SSG)** and **Server-side Rendering (SSR)**.

Together with SWR, you can pre-render the page for SEO, and also have features such as caching, revalidation, focus tracking, refetching on interval on the client side.

You can use the `cacheData` option of [`SWRConfig`](/docs/global-configuration) to pass server-fetched data into the cache for all SWR hooks inside the boundary.

For example with `getStaticProps`:

```jsx
 export async function getStaticProps () {
  // `getStaticProps` is executed on the server side.
  const article = await getArticleFromAPI()
  return {
    props: {
      cacheData: {
        '/api/article': article
      }
    }
  }
}

function Article() {
  // `data` is available from the server-provided `cacheData`.
  const { data } = useSWR('/api/article', fetcher)
  return <h1>{data.title}</h1>
}

export default function Page({ cacheData }) {
  // SWR hooks inside the `SWRConfig` boundary will use those values.
  return (
    <SWRConfig value={{ cacheData }}>
      <Article />
    </SWRConfig>
  )
}
```

The page is still pre-rendered. It's SEO friendly, fast to response, but also fully powered by SWR on the client side. The data can be dynamic and self-updated over time.

<Callout emoji="💡">
  The `Article` component renders the pre-generated data and hydrates it into the client cache without a duplicate initial request. Later revalidation events still use the client fetcher.
</Callout>

### Complex Keys

`useSWR` can be used with keys that are `array` and `function` types. When creating `cacheData` manually, serialize these keys with `unstable_serialize`.

```jsx
import useSWR, { unstable_serialize } from 'swr'

export async function getStaticProps () {
  const article = await getArticleFromAPI(1)
  return {
    props: {
      cacheData: {
        // unstable_serialize() array style key
        [unstable_serialize(['api', 'article', 1])]: article,
      }
    }
  }
}

function Article() {
  // using an array style key.
  const { data } = useSWR(['api', 'article', 1], fetcher)
  return <h1>{data.title}</h1>
}

export default function Page({ cacheData }) {
  return (
    <SWRConfig value={{ cacheData }}>
      <Article />
    </SWRConfig>
  )
}
```
