Deploying Next.js to Static Export with Docker
The Challenge
When building my portfolio, I wanted the best of both worlds: the developer experience of Next.js and the simplicity of static hosting. The output: 'export' configuration in Next.js makes this possible, but there are nuances to understand.
Why Static Export?
Static sites offer significant advantages:
- Performance — no server-side rendering at request time
- Security — no server to compromise
- Cost — host on any static hosting (S3, Cloudflare Pages, Nginx)
- Reliability — nothing to go wrong at runtime
The Configuration
The key configuration in next.config.mjs:
const nextConfig = {
output: 'export',
images: {
unoptimized: true,
},
};Important: When using
output: 'export', Next.js Image Optimization is not available. You must setimages.unoptimized: trueor use a third-party image loader.
Dynamic Routes with Static Export
Dynamic routes like /blog/[slug] require generateStaticParams to tell Next.js which pages to pre-render:
export function generateStaticParams() {
return posts.map((post) => ({
slug: post.slug,
}));
}
export default function BlogPost({ params }: { params: { slug: string } }) {
const post = posts.find((p) => p.slug === params.slug);
// render post...
}Docker Deployment
For containerized deployment, a multi-stage Dockerfile keeps the image small:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/out /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.confThe resulting image is roughly 25MB — just Nginx serving static files.
Nginx Configuration
A minimal Nginx config for SPA-style routing:
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri.html $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}Results
The portfolio loads in under 500ms on average, scores 100/100 on Lighthouse performance, and costs essentially nothing to host. The static export approach combined with Docker gives me flexibility to deploy anywhere — from a $5 VPS to a Kubernetes cluster.
Key Takeaways
- Static export is perfect for content-heavy sites that don't need real-time data
generateStaticParamsis essential for any dynamic routes- Multi-stage Docker builds keep production images minimal
- Nginx caching headers dramatically improve repeat visits
Agamya Samuel
Software Developer & Cloud Architect