Next.js Static Export vs Server: Picking the Right Output
Compare Next.js static export and server runtime modes. Understand when each shines, how features differ, and how to choose without painting yourself into a corner.
What you'll learn
- ✓The capability differences between output modes
- ✓How hosting cost scales for each
- ✓Which features force you to use a server
- ✓How to hybrid-render with ISR
- ✓Migrating between modes without rewriting
Prerequisites
- •Familiar with HTTP and JS
- •Some Next.js experience
What and Why
Next.js can produce two very different kinds of output. A static export (output: 'export') writes plain HTML, CSS, and JS files that any static host can serve. A server build keeps a Node.js process running to handle requests, render pages, and execute server actions. The choice has long-lasting consequences for cost, capabilities, and complexity.
This article gives you a clear decision framework so you do not pick wrong and have to migrate later under pressure.
Mental Model
Treat the two modes as different products that share a syntax. A static export is a deployment artifact; a server build is an application. Static is cheap, fast, and limited. Server is flexible, dynamic, and operationally heavier.
Most non-trivial apps end up server-rendered, but plenty of marketing sites, docs, and dashboards behind a login do beautifully as static exports.
Hands-on Example
Let us look at the same project under both modes.
Static export:
Browser -> CDN -> /about/index.html (no compute)
Server build:
Browser -> CDN -> Node.js -> render React -> HTML
|
+-> DB / API / cookies
ISR (hybrid):
Browser -> CDN -> cached HTML (until revalidate window)
|
+-> background regeneration Enable static export with one line:
// next.config.js
module.exports = { output: "export", images: { unoptimized: true } };
Run next build and you get an out/ directory you can ship to any static host: S3, Cloudflare Pages, GitHub Pages, even a USB stick.
The same project as a server build keeps output unset and is deployed to a Node-capable platform. Server features now work:
// app/dashboard/page.tsx
import { cookies } from "next/headers";
export default async function Dashboard() {
const token = cookies().get("session")?.value;
const data = await fetch("https://api.example.com/me", {
headers: { Authorization: `Bearer ${token}` },
cache: "no-store",
}).then((r) => r.json());
return <h1>Hello, {data.name}</h1>;
}
That page cannot exist in a static export. There is no server to read cookies, no server to call APIs with secrets, no server to render per request.
Feature comparison cheat sheet:
| Feature | Static export | Server build |
|---|---|---|
getStaticProps / RSC fetch | Yes | Yes |
cookies(), headers() | No | Yes |
| Server Actions | No | Yes |
| API routes | No | Yes |
| ISR (revalidate) | No | Yes |
| Image optimization | No | Yes |
| Middleware | No | Yes |
| Hosting cost | ~free | per-request |
Common Pitfalls
- Adopting static export and then needing one cookie-aware page. You either move to server or split into two deployments, both painful.
- Assuming static is always faster. With a warm CDN, server-rendered ISR pages serve from the edge just as fast.
- Forgetting that
next/imageneeds the optimizer. In static mode you must setunoptimized: trueand lose responsive variants. - Using
dynamic = 'force-dynamic'in a static export project. Build fails with a confusing error about no compatible output. - Mixing client-side data fetching with claims of “static site”. The HTML is static, but the page is only useful once JS loads and hits an API, which is its own server.
Practical Tips
- Default to a server build for product apps. The flexibility is worth the operational cost on day one.
- Use static export for docs, landing pages, and tools that genuinely have no per-user state.
- If cost matters, look at ISR before static export. You get most of the speed and keep the capabilities.
- For static exports, host on a CDN that supports clean URLs and custom 404s. Otherwise you fight the platform.
- Run
next buildin CI for both modes if you switch frequently. Some bugs only show up in one. - Keep server code (route handlers, Server Actions) in clearly named folders so it is obvious what breaks under static export.
Wrap-up
Static export and server builds are two different deployment targets that share a developer experience. Static is cheap and simple but capped in capability. Server is powerful but adds operational surface. The right choice depends less on personal preference and more on whether your pages depend on the current request. If they do, pick server. If they truly do not, enjoy the simplicity of a static export. And if you are unsure, server with ISR is a forgiving middle ground that scales in both directions.
Related articles
- Next.js Next.js Data Fetching Patterns: A Practical Guide
Compare the main Next.js data fetching strategies and learn when to use server components, route handlers, SWR, or static generation in your apps.
- Next.js Next.js ISR vs SSR vs SSG
A clear comparison of static, server-rendered, and incrementally regenerated pages in Next.js, with rules for choosing the right strategy.
- Astro Astro vs Next.js Comparison
Compare Astro and Next.js across rendering models, performance defaults, ecosystem, and use cases to pick the right framework for your project.
- Next.js Next.js Caching Strategies Explained
Walk through the four caching layers in Next.js App Router and learn how to choose static, ISR, dynamic, or per-request fetch caching.