Next.js
Deploy a Next.js app on Belune.
Belune's Railpack builder auto-detects a Next.js project and builds it with
next build. We recommend reading the notes below before you deploy.
Prerequisites
Before deploying, decide how Next builds your app (the output mode) and how it reads
configuration (environment variables and the port it listens on). Each one changes how
the app runs on Belune.
Output as Default, export or standalone
The output key in next.config.js decides whether your app runs as a Node server or
ships as static files — and that changes how you deploy it:
output | What runs | What it supports | On Belune |
|---|---|---|---|
| unset (default) | A Node server (next start) | Everything — SSR, ISR, Route Handlers, Middleware, Server Actions | Railpack builds and runs it |
'standalone' | A minimal Node server (server.js, only traced dependencies) | Same as the default | Railpack not supported, needs a Dockerfile running node server.js |
'export' | Nothing — static files in out/ | SSG only: no SSR, ISR, Route Handlers, Middleware, or Server Actions | Serve out/ as static files (no Node server) |
The default output is the simplest on Belune, Railpack builds it and runs
next start, no extra files. standalone produces a smaller image (it traces
only the dependencies the server needs), but Railpack can't run it, you will need to
deploy with a small Dockerfile that runs node server.js (below).
`output: 'export'` Drops Every Request-Time Feature
A static export has no server, so SSR, ISR, Route Handlers, Middleware, Server Actions, and the built-in Image Optimization all stop working, only pre-rendered pages ship.
To serve the exported out/ directory, follow the same two methods as a
Vite single-page app, Railpack SPA mode pointed at out, or a
Caddy Dockerfile.
Use it only for a fully static site, otherwise stay on the default or standalone
output.
Runnable examples for each output mode are on GitHub:
default,
standalone,
and export.
The standalone Dockerfile
Railpack can serve the default and export outputs without a Dockerfile,
but not standalone. next build with output: 'standalone' emits
.next/standalone, but not the static assets or public/, so a Dockerfile has to
copy those in too:
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production PORT=8080
# standalone doesn't bundle these — copy them in explicitly
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
EXPOSE 8080
CMD ["node", "server.js"]Belune's build detector prefers a Dockerfile, so adding one switches off Railpack
automatically. It listens on 8080 as Belune's default, so no Container Port
override is needed.
Environment Variables
Two kinds, and the difference matters:
NEXT_PUBLIC_*: inlined into the client bundle at build time. Set them before the first build; changing one later needs a rebuild, not just a reload. Never put secrets here — they ship in plaintext to the browser.- Server-side variables (database URLs, API secrets): read at runtime, so a reload picks up a change with no rebuild.
Guaranteeing Runtime Server Env
A server variable can still get baked in if it's read while a page is statically prerendered at build. To force per-request evaluation, opt the route into dynamic rendering with:
- Dynamically rendered pages/components, e.g.
cookies(),headers(), setexport const dynamic = 'force-dynamic',fetch(..., { cache: 'no-store' }), etc. connection()async function.
See Next's self-hosting guide for more info.
Serve with Port
Belune routes each domain to container port 8080 by default, while Next server
listens on 3000 unless told. So either:
- Set
PORT=8080on the Environment tab —next startand the standalone server both honor it. - Or leave Next on
3000and set the domain's Container Port to3000.
Caching and ISR
Next's data and ISR cache lives inside the container, so it resets on each deploy. If you rely on Incremental Static Regeneration and want the cache to survive redeploys, persist Next's cache directory with a volume, or point Next at a shared store (such as Redis) with a custom cache handler — see Next's self-hosting guide.