Skip to content

Deploy Next.js

Next.js is a first-class citizen on Stackpad. This guide covers everything you need to know to deploy and optimize a Next.js app.

Quick deploy

  1. Push your Next.js project to GitHub
  2. Create a new project on Stackpad and select your repo
  3. Stackpad detects Next.js automatically and configures the build
  4. Your app is live at your-project.your-org.stackpad.eu

Standalone output (important)

Add output: 'standalone' to your next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
};
export default nextConfig;

This tells Next.js to create a minimal production bundle that:

  • Starts faster — only includes the files needed to run
  • Uses less memory — no full node_modules in the container
  • Builds smaller images — significantly smaller Docker image

Environment variables

Next.js has two types of environment variables:

PrefixAvailable atBundled into JSNeeds rebuild to change
NEXT_PUBLIC_*Build time + client-sideYesYes
No prefixRuntime only (server-side)NoNo

NEXT_PUBLIC_* variables are embedded into the JavaScript bundle at build time. If you change them, you need to rebuild — changing the env var alone won’t update the client-side code.

Server-side variables (without the NEXT_PUBLIC_ prefix) are read at runtime from process.env. Changing them and redeploying applies the new value without a rebuild.

Set your variables in the Stackpad dashboard before deploying:

  • NEXT_PUBLIC_API_URL — your API endpoint (requires rebuild to change)
  • DATABASE_URL — auto-injected if you have PostgreSQL (server-side only)
  • NEXTAUTH_SECRET — for NextAuth.js authentication
  • NEXTAUTH_URL — set to your production URL

Port

Stackpad auto-detects port 3000 for Next.js. No configuration needed.

Adding a database

Most Next.js apps need a database. Add PostgreSQL to your project:

  1. Click Add Service in your project
  2. Select PostgreSQL
  3. Redeploy your Next.js service to pick up the DATABASE_URL

Your Next.js app can now connect to PostgreSQL:

// With Drizzle ORM
import { drizzle } from 'drizzle-orm/node-postgres';
const db = drizzle(process.env.DATABASE_URL!);
// With Prisma
// prisma/schema.prisma:
// datasource db {
// provider = "postgresql"
// url = env("DATABASE_URL")
// }

Database migrations

Add migration to your build script in package.json:

{
"scripts": {
"build": "prisma migrate deploy && next build"
}
}

DATABASE_URL is available at build time, so migrations run before the app starts.

At startup (alternative)

For Drizzle or custom migration scripts, run migrations when the app starts. Be aware this adds to startup time — keep it under 90 seconds total or the health check will fail.

Monorepo setup

If your Next.js app is in a monorepo (e.g. apps/web):

  1. Set Root directory to apps/web in the service settings
  2. Stackpad detects the pnpm workspace and installs from the root
  3. The build runs inside apps/web

Make sure your next.config.js handles the standalone output path correctly for monorepos:

const nextConfig = {
output: 'standalone',
outputFileTracing: '../..', // trace from monorepo root
};

Common issues

IssueSolution
Slow startup (health check timeout)Add output: 'standalone' to reduce startup time
NEXT_PUBLIC_* not updatingThese are build-time — redeploy after changing
Large deployment sizeUse standalone output mode
Database connection errorsRedeploy after adding PostgreSQL to pick up DATABASE_URL
Build timeout (10 min)Check for unnecessary dependencies, optimize next.config.js

What’s next?