Deploy Next.js on Temps
Deploy Next.js on your own infrastructure and skip the Vercel bill — full SSR, API routes, middleware, image optimization, and ISR, all running on a VPS you control with automatic HTTPS.
Prerequisites
- A running Temps instance (quickstart)
- A Next.js project in a GitHub or GitLab repository
- Node.js 18+ in your project (Temps auto-detects this)
Required: Standalone Output
Temps runs Next.js as a persistent Node.js process. Your next.config.ts (or next.config.js) must include output: 'standalone':
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
};
export default nextConfig;
If this is missing, the deployment will succeed but your app will not start. Temps will show a health check failure in the deployment logs.
output: 'standalone' bundles only the files your app needs to run, which makes the Docker image smaller and startup faster. It is also recommended by the Next.js team for containerized deployments.
Quickstart
Deploy your Next.js app
- 1
Add output: 'standalone' to your next.config.ts before deploying, or the app will build but fail its health check.
- 2
Go to Projects then New Project in the dashboard.
- 3
Connect your GitHub or GitLab repository.
- 4
Temps detects Next.js and configures the build automatically.
- 5
Click Deploy. Your app goes live with HTTPS in about 2 minutes.
Checkpoint: Open the deployment and confirm the health check passes and the assigned URL serves your app.
First, authenticate the CLI against your Temps instance (one time per machine):
# Replace with your own Temps URL, then approve in the browser npx @temps-sdk/cli login https://temps.example.com
up only works after login succeeds — it needs the credentials saved by the login step. See the CLI getting started guide for the full authentication flow.
From your Next.js project root, deploy with your preferred package manager:
npx @temps-sdk/cli up
Or via the Temps dashboard:
- Go to Projects → New Project
- Connect your repository
- Temps detects Next.js and configures the build automatically
- Click Deploy — your app is live with HTTPS in about 2 minutes (assuming
output: 'standalone'is set — see the section above)
What Temps handles automatically
Temps automates build, TLS, port binding, ISR, image optimization, middleware, preview deployments, zero-downtime deploys, and rollbacks — you can trigger a rollback from the dashboard or CLI at any time.
Roll back a deployment
- 1
Open your project in the dashboard and go to the Deployments tab.
- 2
Find a previous successful deployment and choose Rollback (one click).
- 3
Confirm the rollback.
Checkpoint: Confirm the rollback target now appears as the most recent deployment in the list.
| Feature | How Temps handles it |
|---|---|
| Build | next build with standalone output |
| HTTPS | Let's Encrypt certificate, auto-renewed |
| Port | Binds to port 3000 by default |
| ISR | Fully supported — cache persists across deploys |
| Image optimization | next/image works with no config changes |
| Middleware | Runs in Node.js runtime (not Edge) |
| Preview deployments | Every PR gets its own URL |
| Rollbacks | One click in dashboard or temps rollback CLI command |
| Zero-downtime deploys | New container starts before old one stops |
Environment Variables
Set an environment variable
- 1
Open your project and go to Settings then Environment Variables.
- 2
Add the variable name and value, e.g. DATABASE_URL.
- 3
Pick the environment it applies to (production), or leave it across all environments.
- 4
Save the variable.
Checkpoint: Confirm the variable appears in the Environment Variables list for the chosen environment. Runtime variables apply on next request; NEXT_PUBLIC_ variables require a rebuild.
Set variables in Project → Settings → Environment Variables or via CLI:
The -e flag is the short form of --environments (plural). It accepts a comma-separated list of environment names, for example -e production,staging.
# Set a variable for production npx @temps-sdk/cli environments vars set DATABASE_URL "postgres://user:pass@host:5432/db" -e production # Set a variable for all environments npx @temps-sdk/cli environments vars set NEXT_PUBLIC_API_URL "https://api.yourdomain.com"
Variables prefixed with NEXT_PUBLIC_ are embedded at build time. All other variables are available at runtime only — you do not need to rebuild when you change them.
Redeploy after a runtime variable change
- 1
Open your project in the dashboard and go to the Deployments tab.
- 2
Trigger a new deployment for the target environment (production).
- 3
Wait for the new deployment to finish.
Checkpoint: Confirm the latest deployment is live and serving the updated runtime variable.
# After changing a runtime variable, trigger a redeploy npx @temps-sdk/cli deploy --project my-app
API Routes and Route Handlers
API routes (/app/api/ or /pages/api/) work without any changes. Temps runs your app as a persistent Node.js process, so there are no cold starts — the first request is as fast as any subsequent one.
// app/api/hello/route.ts — works on Temps without changes
export async function GET() {
return Response.json({ message: "Hello from Temps" });
}
Middleware
Next.js Middleware runs on Temps in the Node.js runtime (not the Edge runtime). This means:
- All Node.js APIs are available
- No
export const runtime = 'edge'required - No limitations on package size
If your middleware currently uses Edge-only APIs, remove export const runtime = 'edge' and test locally with NODE_ENV=production.
ISR and Caching
Persist the ISR cache across deploys
- 1
Open your project and go to Settings then Volumes.
- 2
Mount a volume at /app/.next/cache.
Checkpoint: Confirm the volume shows as mounted at /app/.next/cache, then redeploy and verify ISR pages are served from cache without regenerating.
Incremental Static Regeneration (ISR) works on Temps. The cache is stored on disk inside the container, so it persists between requests.
On redeploy, Temps starts the new container before stopping the old one (zero-downtime). The new container starts with a cold cache, so the first request to each ISR page after a deploy will regenerate it. This is the expected behavior — subsequent requests are served from cache.
If you need the ISR cache to persist across deploys, mount a persistent volume:
- Go to Project → Settings → Volumes
- Mount a volume at
/app/.next/cache
Monorepos
If your Next.js app is inside a monorepo, set the App Directory in project settings to the subdirectory containing package.json:
my-monorepo/
├── apps/
│ └── web/ ← set App Directory to "apps/web"
│ ├── package.json
│ └── next.config.ts
└── packages/
See Deploy a Project for workspace-aware builds.
Troubleshooting
Health check failing after deploy
The most common cause is missing output: 'standalone' in next.config.ts. Check the deployment logs — if you see ENOENT .next/standalone/server.js, that is the problem.
# View live deployment logs npx @temps-sdk/cli deployments logs --project my-app --follow
Build running out of memory
Next.js builds can be memory-intensive. If the build fails with an out-of-memory error:
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Set a higher memory limit as an environment variable in your project settings:
NODE_OPTIONS=--max-old-space-size=4096
Environment variables not available at runtime
Check that the variable is set in the correct environment (production vs staging). Variables set in the Temps console are not available at build time unless they are prefixed with NEXT_PUBLIC_.
next/image returning 404 for external images
Add your image domains to next.config.ts:
const nextConfig: NextConfig = {
output: "standalone",
images: {
remotePatterns: [
{ protocol: "https", hostname: "your-image-cdn.com" },
],
},
};
Port mismatch
Temps expects your app to listen on port 3000 by default. If your next.config.ts or start script uses a different port, override it with an environment variable:
PORT=3000
Switching from Vercel
If you're migrating from Vercel, see the Migrate from Vercel guide. Most Next.js apps migrate in under 30 minutes — the main changes are replacing Vercel-specific storage (KV, Blob, Postgres) with standard alternatives.
Platform behavior
These rules apply to every app deployed on Temps, regardless of framework.
The one requirement: your app must listen on the port in the PORT environment variable and bind to 0.0.0.0 — not localhost or 127.0.0.1. Temps runs your app in a container and routes traffic from the host, so an app bound to localhost only accepts connections from inside the container and will fail its health check.
Health checks
After your container starts, Temps sends HTTP GET requests to verify it is healthy before routing traffic to it.
- Path:
/(the root of your application) - Success: 2 consecutive responses with a 2xx or 3xx status code
- Timeout: 300 seconds (5 minutes) for the app to become healthy
- Retry interval: every 5 seconds
Connection errors while the app is still starting are retried without penalty. If the app returns 4xx or 5xx errors for 60 consecutive seconds, the deployment fails. Customize the check by adding a .temps.yaml to your repository root:
health:
path: /health
status: 200
interval: 30
timeout: 5
retries: 3/health endpoint that returns a simple 200. This avoids issues where / requires authentication or returns a redirect.Auto-injected environment variables
Temps injects these variables into every deployment automatically:
| Variable | Value | Description |
|---|---|---|
PORT | Resolved port | The port your app must listen on |
HOST | 0.0.0.0 | Bind address |
SENTRY_DSN | Auto-generated | Error tracking endpoint |
TEMPS_API_URL | Your Temps URL | Platform API endpoint |
TEMPS_API_TOKEN | Deployment token | Authentication for Temps SDKs |
OTEL_EXPORTER_OTLP_ENDPOINT | Your Temps OTLP URL | OpenTelemetry trace collection |
OTEL_SERVICE_NAME | Project name | Service identifier for traces |
You do not need to configure these manually. They are available in process.env (Node.js), os.environ (Python), os.Getenv (Go), and the equivalent in other languages.