Self-hosted deploy previews for Next.js
Push a branch, get a live preview URL. PreviewDrop builds your Next.js app in standalone mode, runs it as a real Node process, and posts the link to the pull request, usually within a couple of minutes — on your own infra, password-protected, flat-priced.
output: 'standalone' in next.config, connect your repo, push. PreviewDrop detects Next.js, builds the image and runs server.js behind a TLS-terminated subdomain. Full Node runtime — middleware, route handlers, ISR and server actions all work, and previews are password-protected by default.What the build needs to do
You don't write this. PreviewDrop detects Next.jsfrom your repo and builds the container for you — a Dockerfile in your repo is not used. The reference below shows the install, build and start steps a working Next.js image needs. If detection gets one wrong, set the matching Install, Build or Start command in Project Settings. Your app must listen on $PORT.
Reference (not read by PreviewDrop)FROM node:22-slim AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:22-slim WORKDIR /app ENV NODE_ENV=production HOSTNAME=0.0.0.0 # Requires output: 'standalone' in next.config.{js,ts} COPY --from=build /app/.next/standalone ./ COPY --from=build /app/.next/static ./.next/static COPY --from=build /app/public ./public EXPOSE 3000 CMD ["node", "server.js"]
Environment variables
Set these in the Variables tab of your PreviewDrop project. They're encrypted at rest and injected into every preview container at start.
| Variable | Example value | Note |
|---|---|---|
| PORT | 3000 | PreviewDrop injects this; the standalone server.js reads it automatically. |
| DATABASE_URL | postgres://user:pass@host:5432/db | Server-side only env is read at runtime — safe to set here. |
| NEXT_PUBLIC_API_URL | https://api.example.com | NEXT_PUBLIC_* is inlined at BUILD time — see the gotcha below. |
Common gotchas
Set output: 'standalone' in next.config
.next/standalone, which Next.js produces only when output: 'standalone' is set. Without it there’s no server.js to run and the container exits immediately.NEXT_PUBLIC_* vars are baked at build time
NEXT_PUBLIC_ is inlined into the client bundle during npm run build, not read at container start. Set those project variables before the build runs (they’re available as build args), or keep client-side config in non-secret runtime fetches. Server-only secrets are read at runtime and are fine to set normally.Copy static and public into the standalone output
server.js does not include .next/static or public. Both must sit next to it (the reference build above copies them) or your CSS, JS chunks and images 404. If they are missing, set the Build and Start commands in Project Settings to do the same.Bind to 0.0.0.0
HOSTNAME=0.0.0.0 (PreviewDrop sets it in the container) so the standalone server listens on all interfaces. The default can bind to localhost inside the container, which the proxy can’t reach.Why not Vercel or Netlify?
Preview your Next.js app in 5 minutes
Connect a repo, push a branch, get a URL. No credit card, no trial clock.
Start free