Deploy Next.js
deploybase serves static files, so Next.js has to run in static export mode. That is one line of config, plus a decision about any feature in your app that expects a server.
Turn on static export
Section titled “Turn on static export”/** @type {import('next').NextConfig} */const nextConfig = { output: 'export',};
module.exports = nextConfig;next build then writes a complete site to out/ instead of starting a server. Next.js 13.3 and later support this; on older versions you need next export as a separate step.
Build defaults
Section titled “Build defaults”| Setting | Value |
|---|---|
| Build command | npm run build |
| Output directory | out |
| Image | node:24-alpine |
Every value above is editable per project, and the full defaults table covers the other frameworks.
What static export gives up
Section titled “What static export gives up”Next.js fails the build for most of these rather than deploying something subtly broken, which is the behaviour you want:
| Feature | Status | What to do instead |
|---|---|---|
| API routes, route handlers | Not available | Call an API from the browser, or use Forms for submissions |
| Middleware | Not available | Redirects and rewrites at the edge, or client-side routing |
getServerSideProps |
Not available | getStaticProps, fetching at build time |
| Incremental static regeneration | Not available | Redeploy when content changes. A webhook from your CMS to the deploy API rebuilds in seconds |
| Server Components doing runtime work | Build time only | They run during the build, so their data is frozen into the HTML |
next/image default loader |
Needs config | See below |
Draft mode, cookies(), headers() |
Not available | Nothing is running per request to read them |
If your app depends on several of these, static export is the wrong shape for it, and deploybase is the wrong host for it. Better to know that before a migration than after one.
Configure images
Section titled “Configure images”The default image loader optimises on demand, which needs a server:
const nextConfig = { output: 'export', images: { unoptimized: true },};unoptimized: true ships your images as they are, so size them before committing them. Alternatively point images.loader at an external service, which keeps next/image responsive srcsets while the transformation happens elsewhere.
Decide on trailing slashes early
Section titled “Decide on trailing slashes early”A static export writes about.html by default. Most static hosts, ours included, serve /about from about/index.html:
const nextConfig = { output: 'export', trailingSlash: true,};This is worth settling before the site has traffic, because changing it later changes every URL on the site and costs you the search rankings attached to them.
Only NEXT_PUBLIC_ variables reach the browser
Section titled “Only NEXT_PUBLIC_ variables reach the browser”Environment variables are injected during the build. Next.js inlines the NEXT_PUBLIC_-prefixed ones into the client bundle and keeps the rest to build-time code. Because there is no server, a non-public variable is readable only by getStaticProps and friends while the build runs.
A NEXT_PUBLIC_ value is published in your JavaScript. Treat it as public.
When it breaks
Section titled “When it breaks”Page "/blog/[slug]" is missing "generateStaticParams()". A dynamic route has no list of pages to write. Export generateStaticParams (App Router) or getStaticPaths (Pages Router) returning every slug.
export const dynamic = "force-dynamic" errors at build. That route is asking for per-request rendering. Remove the directive, or move the work into the browser.
The deploy is empty, or 404s everywhere. output: 'export' is missing, so next build produced .next/ rather than out/. Add it and redeploy.
Images 404 in production but work in next dev. The default loader is still configured. Set images.unoptimized.
Routes work on the first load but 404 on refresh. Trailing-slash handling does not match how the files were written. Set trailingSlash: true and redeploy.
Live a8b7eb1d built