Building Single-Page Applications (SPAs) with Next.js – Client Rendering, Fast Navigation, and Dynamic Data Fetching

Next.js fully supports building SPAs with client-side rendering, fast transitions, and dynamic data fetching. This article explores common patterns for building SPAs using context, SWR, React Query, Server Actions, and shallow routing — while allowing you to progressively adopt server features as your app grows.

SPAClient RenderingSWRReact Query

~2 min read • Updated Oct 28, 2025

What Is a SPA?


A Single-Page Application (SPA) is an app where all rendering, navigation, and data fetching happen in the browser. There are no full-page reloads — everything is handled by JavaScript.


Why Use Next.js for SPAs?


  • Automatic code splitting and reduced bundle size
  • Fast navigation with next/link and prefetching
  • Start as a SPA and progressively add server features

Data Fetching with Context and use()


Start data fetching in the root layout and pass the Promise to a context provider:

// app/layout.tsx
let userPromise = getUser()

<UserProvider userPromise={userPromise}>
  {children}
</UserProvider>

Then in a client component:

// app/profile.tsx
const { userPromise } = useUser()
const user = use(userPromise)

This pattern enables partial hydration and streaming.


Using SWR in SPAs


With SWR, you can fetch data on the client or server:

// app/layout.tsx
<SWRConfig value={{ fallback: { '/api/user': getUser() } }}>
  {children}
</SWRConfig>

// app/profile.tsx
const { data, error } = useSWR('/api/user', fetcher)

Initial data is prerendered and read by SWR in the browser.


Using React Query


React Query works with Next.js on both client and server, allowing flexible data fetching strategies.


Rendering Only in the Browser


To disable prerendering for a client component:

const ClientOnlyComponent = dynamic(() => import('./component'), {
  ssr: false,
})

Shallow Routing in the Client


To update the URL without reloading the page:

window.history.pushState(null, '', `?sort=asc`)

Then read the value using useSearchParams.


Using Server Actions in Client Components


Call server-side logic directly from the client without creating an API route:

// app/button.tsx
import { create } from './actions'

<button onClick={() => create()}>Create</button>

Static Export (Optional)


Next.js also supports generating a fully static site, which can offer performance advantages over strict SPAs in some cases.


Conclusion


Next.js is a powerful framework for building SPAs — with client-side rendering, fast navigation, and dynamic data fetching. Using context, SWR, React Query, and Server Actions, you can build a flexible, performant, and scalable application.


Written & researched by Dr. Shahin Siami