nextjs-despliegue-vps-docker

Next.js Deployment

  • 4 min

We’ve reached the end of the road. We have a fast, optimized, and functional application. Now the big question arises: Where do we host it?

If you search on Google, 99% of the tutorials will tell you: “Use Vercel” (the creators of Next.js). Vercel has a wonderful PaaS platform. It’s a one-click solution.

But depending on a single provider is a risk. Furthermore, the costs of Serverless platforms can skyrocket if your app scales. Sometimes, the right solution is a €5/month VPS or an S3 bucket.

Today we’re going to see how to take Next.js out of its “home” and deploy it on any infrastructure 👇.

Understanding the Build

Before uploading anything, we must understand what Next.js generates.

When we run npm run build, Next.js analyzes all our code and creates a hidden folder called .next.

This folder contains:

  1. Static HTML: For pages that are fully static.
  2. Server code: Optimized JS files to run on Node.js (Server Actions, SSR).
  3. Public Assets: Images, fonts, and client-side JS.

To start the application in production mode, we don’t use npm run dev. We use:

npm run start
Copied!

This command starts a local Node.js server that serves what’s in .next. This is the server we need to put online.

Strategy 1: The Node.js Server (VPS)

If you have a VPS (DigitalOcean, Hetzner, AWS EC2) with Linux, you can deploy Next.js “bare-metal”.

Upload the code to the server (git pull).

Install dependencies: npm install --production.

Build: npm run build.

Execute: npm run start.

The problem is that if you close the SSH terminal, the server shuts down. To keep it alive, you need a process manager like PM2.

npm install -g pm2
pm2 start npm --name "my-next-app" -- start
Copied!

This strategy is fragile. If you update the Node version on the server, the app can break. To avoid the “it works on my machine” problem, we use Docker.

Strategy 2: Docker

Docker allows us to package our application, with its exact version of Node.js and its dependencies, in an immutable container.

The trick to keep the Docker image from weighing 1GB is to use a Next.js feature called Standalone Output.

const nextConfig = {
  // This tells Next.js to generate an isolated build with
  // ONLY the node_modules needed for production.
  output: "standalone",
};

export default nextConfig;
Copied!

Don’t copy a basic Dockerfile. Use this optimized one (Multi-stage build):

# STAGE 1: Dependencies
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# STAGE 2: Builder
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# STAGE 3: Runner (Tiny final image)
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV production

# Copy only what's needed from the builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/.next/standalone ./

EXPOSE 3000
CMD ["node", "server.js"]
Copied!

With this, you have a lightweight image that you can deploy anywhere: Kubernetes, AWS ECS, Google Cloud Run, or your VPS with Docker Compose.

Strategy 3: Static Exports (SSG)

Sometimes, you don’t need a server. If your website is a Blog, a Landing Page, or corporate documentation, you don’t need Node.js running 24/7. You can pre-render everything to HTML and CSS.

// next.config.mjs
const nextConfig = {
  output: "export", // 👈 The key
};
Copied!

When you run npm run build, Next.js will no longer create the .next folder. It will create an out folder.

Inside out you’ll have index.html, about.html, etc.

The out folder can be hosted for free or for pennies at:

  • GitHub Pages
  • AWS S3 + CloudFront
  • Nginx / Apache (Classic web server)
  • Cloudflare Pages

Limitations

Since there’s no Node.js server, you lose:

  • ❌ Server Actions (forms won’t work without an external API).
  • ❌ Dynamic Rendering (you can’t read headers or cookies on the server).
  • ❌ Dynamic Image Optimization <Image> with the Next.js server (you need images without an optimizer or an external loader like Cloudinary).

Summary: What Should I Choose?

Decision guide for when you need to take your project to production:

ScenarioRecommended StrategyWhy?
Landing Page / Personal BlogStatic ExportZero cost, unhackable, maximum speed.
SaaS / E-commerceDocker (VPS/Cloud)Full control, support for Server Actions and Databases. Predictable cost.
Fast MVP / HackathonVercel / Netlify1-minute deployment, automatic CI/CD. Beware of cost scaling.