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
- Push your Next.js project to GitHub
- Create a new project on Stackpad and select your repo
- Stackpad detects Next.js automatically and configures the build
- Your app is live at
your-project.your-org.stackpad.eu
Recommended configuration
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_modulesin the container - Builds smaller images — significantly smaller Docker image
Environment variables
Next.js has two types of environment variables:
| Prefix | Available at | Bundled into JS | Needs rebuild to change |
|---|---|---|---|
NEXT_PUBLIC_* | Build time + client-side | Yes | Yes |
| No prefix | Runtime only (server-side) | No | No |
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 authenticationNEXTAUTH_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:
- Click Add Service in your project
- Select PostgreSQL
- Redeploy your Next.js service to pick up the
DATABASE_URL
Your Next.js app can now connect to PostgreSQL:
// With Drizzle ORMimport { 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
During build (recommended for Prisma)
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):
- Set Root directory to
apps/webin the service settings - Stackpad detects the pnpm workspace and installs from the root
- 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
| Issue | Solution |
|---|---|
| Slow startup (health check timeout) | Add output: 'standalone' to reduce startup time |
NEXT_PUBLIC_* not updating | These are build-time — redeploy after changing |
| Large deployment size | Use standalone output mode |
| Database connection errors | Redeploy after adding PostgreSQL to pick up DATABASE_URL |
| Build timeout (10 min) | Check for unnecessary dependencies, optimize next.config.js |
What’s next?
- Environment variables — full scoping guide
- Custom domains — add your own domain
- PostgreSQL — database setup and connection details