Next.js runs on Hangar as a Node.js server in a container. That means the whole framework works, not only static export: server components, route handlers, server actions, middleware and ISR.
Before you start
- A Next.js app in a Git repository, with
buildandstartscripts inpackage.json:
{
"scripts": {
"build": "next build",
"start": "next start"
}
}
1. Create the service
Create a project, add a service and pick your repository and branch. Choose the region closest to your users.
Leave the builder on Automatic. It detects Next.js, uses the package manager your lockfile points to (npm, pnpm, Yarn or Bun), runs build and starts the app with start.
2. Set environment variables
Add your variables in the service's Variables tab.
Next.js inlines every NEXT_PUBLIC_ variable into the browser bundle at build time. Set those as build arguments as well, so they exist while the image is built. Server-only variables are read at runtime and need nothing special.
3. Deploy
Start the deploy and follow the build log. The first build installs every dependency; later builds reuse the cache.
4. Add a domain
In Settings → Networking, generate a domain or add your own, set the container port to 3000 and turn HTTPS on. The certificate is issued and renewed for you. Details in Domains and HTTPS.
5. Push to deploy
Every push to the connected branch now builds and deploys. If a release misbehaves, roll back to the previous deploy from the service's deployments.
Smaller images with standalone output
Optional, but worth it for larger apps. Standalone output copies only the files the server needs:
// next.config.js
module.exports = {
output: "standalone",
};
With standalone output, build with a Dockerfile so you control what is copied into the final image. The Dockerfile guide shows how to deploy one.
Adding a database
Create a PostgreSQL database in the same project and region, copy its internal connection URL and save it as DATABASE_URL. If you use Prisma or Drizzle, run migrations before the server. The simplest way is a script in package.json, which npm runs through a shell:
"start": "prisma migrate deploy && next start"
See Databases.
Troubleshooting
- The domain returns 502: the container port is not
3000, or a custom server listens on127.0.0.1. Listen on0.0.0.0. - A
NEXT_PUBLIC_value is undefined in the browser: it was not available during the build. Add it as a build argument and redeploy. - The build runs out of memory: raise the service's memory limit, or build with a Dockerfile and standalone output.