// notas

Next.js en Docker: standalone y la imagen baja de 1.2 GB a 180 MB

La salida standalone empaqueta solo las dependencias que el servidor usa en tiempo de ejecución. Con multi-stage, la imagen final no lleva ni node_modules completo ni el código fuente.

1 min de lectura
DockerNext.jsDespliegue

Por defecto, meter una app de Next.js en Docker implica arrastrar node_modules completo a la imagen final. Con output: "standalone", Next analiza qué necesita realmente el servidor en ejecución y lo empaqueta aparte.

next.config.ts
const nextConfig = {
  output: "standalone",
};

Y el Dockerfile en tres etapas:

Dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
 
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
 
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S nodejs && adduser -S nextjs -G nodejs
 
COPY --from=build /app/public ./public
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
 
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]

Tres detalles que se me pasaron la primera vez:

.next/static hay que copiarlo aparte. No va dentro de standalone. Si lo olvidas, la app carga pero sin CSS ni JS, y el error en consola es un 404 poco descriptivo.

public/ también va aparte, por la misma razón.

El server.js que ejecutas está en la raíz de standalone, no en .next/. Por eso el COPY lleva ./ como destino.

El resultado: se acabó el npm ci --omit=dev en la imagen final y desaparecen el código fuente y las dependencias de build.

Si esto te resultó útil o tienes un caso parecido en tu empresa, escríbeme: me gusta conversar sobre estos problemas aunque no termine en un proyecto.