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, GitLab, Bitbucket, or Gitea repository
  • A next.config.js, next.config.mjs or next.config.ts file in the project root, which is how Temps detects Next.js

How Temps runs Next.js

Temps builds your app with your package manager's build script and runs it with next start as a persistent Node.js process. You don't need output: 'standalone' in your next.config.ts; the image contains the full build and node_modules.

Temps runs next start directly, so your package.json start script isn't used. If your app needs a custom server (for example a server.js), deploy it with your own Dockerfile instead.

Builds use a Node.js 22 image, and the app runs on Node.js 22 (Alpine). The Node.js version isn't read from your project.


Quickstart

Deploy your Next.js app

  1. 1

    Go to Projects then New Project in the dashboard.

  2. 2

    Connect your GitHub, GitLab, Bitbucket, or Gitea repository.

  3. 3

    Temps detects Next.js and configures the build automatically.

  4. 4

    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:

  1. Go to Projects → New Project
  2. Connect your repository
  3. Temps detects Next.js and configures the build automatically
  4. Click Deploy — your app is live with HTTPS in about 2 minutes

What Temps handles automatically

Temps automates the build, TLS, port binding, zero-downtime deploys and rollbacks, and runs your app the same way next start does anywhere else — you can trigger a rollback from the dashboard or CLI at any time.

Roll back a deployment

  1. 1

    Open your project in the dashboard and go to the Deployments tab.

  2. 2

    Find a previous successful deployment and choose Rollback to this.

  3. 3

    Confirm the rollback.

    Checkpoint: Confirm the rollback target now appears as the most recent deployment in the list.

FeatureHow Temps handles it
BuildYour build script (for example next build), then next start
HTTPSLet's Encrypt certificate, auto-renewed
PortPort 3000 by default; Temps sets PORT and HOSTNAME=0.0.0.0
ISRWorks; the cache lives in the container and starts empty after each deploy
Image optimizationnext/image works as it does under next start
Preview deploymentsOpt-in; once enabled, each branch gets its own preview environment
RollbacksRollback to this in the dashboard or the rollback CLI command
Zero-downtime deploysNew container starts before old one stops

Environment Variables

Set an environment variable

  1. 1

    Open your project and go to Settings then Environment Variables.

  2. 2

    Add the variable name and value, e.g. DATABASE_URL.

  3. 3

    Pick the environments it applies to (for example production).

  4. 4

    Save the variable.

    Checkpoint: Confirm the variable appears in the Environment Variables list for the chosen environment, then redeploy so it takes effect.

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 production and staging
npx @temps-sdk/cli environments vars set NEXT_PUBLIC_API_URL "https://api.yourdomain.com" -e production,staging

If you leave out -e, the CLI asks which environments to set the variable for.

Your project's variables are passed to the build as well as to the running app. Next.js inlines variables prefixed with NEXT_PUBLIC_ into the browser bundle at build time; all other variables are read by the server at runtime.

Variables are applied when a deployment starts, so changing one doesn't affect the running app until you redeploy:

Redeploy after a runtime variable change

  1. 1

    Open your project in the dashboard and go to the Deployments tab.

  2. 2

    Trigger a new deployment for the target environment (production).

  3. 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

Middleware works on Temps without changes. It runs inside the next start server, so the same rules apply as for any self-hosted Next.js app.


ISR and Caching

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 an empty cache, so the first request to each ISR page after a deploy regenerates it, and later requests are served from cache. Temps doesn't offer a persistent volume for the cache; if you need a cache that survives deploys, configure a custom cache handler in Next.js that stores it outside the container.


Monorepos

If your Next.js app is inside a monorepo, set the Root directory in project settings to the subdirectory containing package.json:

my-monorepo/
├── apps/
│   └── web/          ← set Root directory to "apps/web"
│       ├── package.json
│       └── next.config.ts
└── packages/

See Deploy a Project for workspace-aware builds.


Troubleshooting

Health check failing after deploy

Check the deployment logs. A common cause is an app that crashes on startup, for example because of a missing environment variable.

# 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), then redeploy: variables are applied when a deployment starts.

next/image returning 404 for external images

Add your image domains to next.config.ts:

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      { protocol: "https", hostname: "your-image-cdn.com" },
    ],
  },
};

Port mismatch

Temps sets the PORT variable for your app (3000 by default), and next start listens on it. To use a different port, set it under Project → Settings → Build & deploy → Deployment. Setting PORT yourself has no effect, because Temps overrides it.


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:

.temps.yaml
health:
  path: /health
  status: 200
  interval: 30
  timeout: 5
  retries: 3
Add a dedicated /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:

VariableValueDescription
PORTResolved portThe port your app must listen on
HOST0.0.0.0Bind address
SENTRY_DSNAuto-generatedError tracking endpoint
TEMPS_API_URLYour Temps URLPlatform API endpoint
TEMPS_API_TOKENDeployment tokenAuthentication for Temps SDKs
OTEL_EXPORTER_OTLP_ENDPOINTYour Temps OTLP URLOpenTelemetry trace collection
OTEL_SERVICE_NAMEProject nameService 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.


Next Steps

Last updated

Was this page helpful?