Conteneriza una aplicación Next.js
Prerrequisitos
Antes de comenzar, asegúrate de que las siguientes herramientas estén instaladas y disponibles en tu sistema:
- Has instalado la última versión de Docker Desktop.
- Tienes un cliente de git. Los ejemplos de esta sección utilizan un cliente de git basado en la línea de comandos, pero puedes usar cualquier cliente.
¿Eres nuevo en Docker?
Comienza con la guía de conceptos básicos de Docker para familiarizarte con conceptos clave como imágenes, contenedores y Dockerfiles.
Descripción general
Esta guía te guiará a través de la contenerización de una aplicación Next.js con Docker. Aprenderás a crear una imagen de Docker lista para producción utilizando las mejores prácticas que mejoran el rendimiento, la seguridad, la escalabilidad y la eficiencia del despliegue.
Al final de esta guía, lograrás lo siguiente:
- Contenerizar una aplicación Next.js usando Docker.
- Crear y optimizar un Dockerfile para construcciones de producción.
- Usar construcciones multi-etapa (multi-stage) para minimizar el tamaño de la imagen.
- Aprovechar la salida standalone o export de Next.js para una contenerización eficiente.
- Seguir las mejores prácticas para construir imágenes de Docker seguras y fáciles de mantener.
Obtener la aplicación de ejemplo
Clona la aplicación de ejemplo para usarla con esta guía. Abre una terminal, cambia al directorio en el que deseas trabajar y ejecuta el siguiente comando para clonar el repositorio de git:
$ git clone https://github.com/kristiyan-velkov/docker-nextjs-sample
Generar un Dockerfile
Docker proporciona una herramienta de CLI interactiva llamada docker init que ayuda a andamiar (scaffold) los archivos de configuración necesarios para contenerizar tu aplicación. Esto incluye la generación de un Dockerfile, .dockerignore, compose.yaml y README.Docker.md.
Para comenzar, navega al directorio del proyecto:
$ cd docker-nextjs-sample
Luego ejecuta el siguiente comando:
$ docker init
Verás una salida similar a:
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
Let's get started!La CLI te hará algunas preguntas sobre la configuración de tu aplicación. Para mantener la consistencia, utiliza las mismas respuestas que se muestran en el siguiente ejemplo cuando se te solicite:
| Question | Answer |
|---|---|
| What application platform does your project use? | Node |
| What version of Node do you want to use? | 24.14.0-alpine |
| Which package manager do you want to use? | npm |
| Do you want to run "npm run build" before starting server? | yes |
| What directory is your build output to? | .next |
| What command do you want to use to start the app? | npm run start |
| What port does your server listen on? | 3000 |
Después de completarlo, el directorio de tu proyecto contendrá los siguientes archivos nuevos:
├── docker-nextjs-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ └── README.Docker.mdConstruir la imagen de Docker
El Dockerfile predeterminado generado por docker init sirve como un punto de partida sólido para aplicaciones generales de Node.js. Sin embargo, Next.js tiene requisitos específicos para despliegues de producción. Esta guía muestra dos enfoques: salida standalone (servidor Node.js) y salida export (archivos estáticos con NGINX).
Paso 1: Revisar los archivos generados
En este paso, agregarás un Dockerfile y archivos de configuración siguiendo las mejores prácticas:
- Usar construcciones multi-etapa para mantener la imagen final limpia y pequeña.
- Standalone: Node.js ejecuta el servidor Next.js; Export: NGINX sirve archivos estáticos desde la exportación.
- Mejorar el rendimiento y la seguridad incluyendo solo lo necesario.
Estas actualizaciones ayudan a asegurar que tu aplicación sea fácil de desplegar, rápida de cargar y lista para producción.
NoteUn
Dockerfilees un archivo de texto plano que contiene instrucciones paso a paso para construir una imagen de Docker. Automatiza el empaquetado de tu aplicación junto con sus dependencias y el entorno de ejecución.
Para obtener detalles completos, consulta la referencia de Dockerfile.
Paso 2: Configurar la salida de Next.js y el Dockerfile
Antes de crear un Dockerfile, elige una imagen base: la Imagen Oficial de Node.js o una Imagen Endurecida de Docker (Docker Hardened Image - DHI) del catálogo de imágenes endurecidas. Elegir una DHI te brinda una imagen segura, ligera y lista para producción. Para más información, consulta Docker Hardened Images.
ImportantEsta guía utiliza etiquetas de imagen Node.js LTS estables que se consideran seguras cuando se escribió la guía. Debido a que se publican nuevos lanzamientos y parches de seguridad regularmente, revisa siempre las imágenes oficiales de Docker de Node.js y selecciona una versión segura y actualizada antes de construir o desplegar.
2.1 Next.js con salida standalone
La salida standalone (output: "standalone") hace que Next.js compile una salida autocontenida que incluye únicamente los archivos y dependencias necesarios para ejecutar la aplicación. Un simple node server.js puede servir la aplicación, lo cual es ideal para Docker y soporta el renderizado en el lado del servidor (SSR), rutas de API y la regeneración estática incremental (ISR). Para obtener más detalles, consulta la documentación de configuración de salida de Next.js (incluyendo la opción "standalone").
El contenedor ejecuta el servidor Next.js con Node.js en el puerto 3000.
Configura Next.js — Abre o crea next.config.ts en la raíz de tu proyecto:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
};
export default nextConfig;Elige una Imagen Endurecida de Docker o la Imagen Oficial de Docker, luego crea o reemplaza tu Dockerfile con el contenido de la pestaña seleccionada a continuación.
Las Docker Hardened Images (DHIs) están disponibles para Node.js en el catálogo de Docker Hardened Images. Para más información, consulta la guía de inicio rápido de DHI.
Inicia sesión en el registro de DHI:
$ docker login dhi.ioDescarga la DHI de Node.js (consulta el catálogo para ver las versiones disponibles):
$ docker pull dhi.io/node:24-alpine3.22-devReemplaza el Dockerfile generado con el siguiente. Las instrucciones
FROMutilizandhi.io/node:24-alpine3.22-dev. Consulta el catálogo de Docker Hardened Images para obtener las últimas versiones y actualiza las etiquetas de la imagen según sea necesario para la seguridad y compatibilidad.# ============================================ # Stage 1: Dependencies Installation Stage # ============================================ # IMPORTANT: Docker Hardened Image (DHI) Version Maintenance # This Dockerfile uses dhi.io/node. Regularly validate and update to the latest DHI versions in the catalog for security and compatibility. FROM dhi.io/node:24-alpine3.22-dev AS dependencies # Set working directory WORKDIR /app # Copy package-related files first to leverage Docker's caching mechanism COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ # Install project dependencies with frozen lockfile for reproducible builds RUN --mount=type=cache,target=/root/.npm \ --mount=type=cache,target=/usr/local/share/.cache/yarn \ --mount=type=cache,target=/root/.local/share/pnpm/store \ if [ -f package-lock.json ]; then \ npm ci --no-audit --no-fund; \ elif [ -f yarn.lock ]; then \ corepack enable yarn && yarn install --frozen-lockfile --production=false; \ elif [ -f pnpm-lock.yaml ]; then \ corepack enable pnpm && pnpm install --frozen-lockfile; \ else \ echo "No lockfile found." && exit 1; \ fi # ============================================ # Stage 2: Build Next.js application in standalone mode # ============================================ FROM dhi.io/node:24-alpine3.22-dev AS builder # Set working directory WORKDIR /app # Copy project dependencies from dependencies stage COPY --from=dependencies /app/node_modules ./node_modules # Copy application source code COPY . . ENV NODE_ENV=production # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the build. # ENV NEXT_TELEMETRY_DISABLED=1 # Build Next.js application # If you want to speed up Docker rebuilds, you can cache the build artifacts # by adding: --mount=type=cache,target=/app/.next/cache # This caches the .next/cache directory across builds, but it also prevents # .next/cache/fetch-cache from being included in the final image, meaning # cached fetch responses from the build won't be available at runtime. RUN if [ -f package-lock.json ]; then \ npm run build; \ elif [ -f yarn.lock ]; then \ corepack enable yarn && yarn build; \ elif [ -f pnpm-lock.yaml ]; then \ corepack enable pnpm && pnpm build; \ else \ echo "No lockfile found." && exit 1; \ fi # ============================================ # Stage 3: Run Next.js application # ============================================ FROM dhi.io/node:24-alpine3.22-dev AS runner # Set working directory WORKDIR /app # Set production environment variables ENV NODE_ENV=production ENV PORT=3000 ENV HOSTNAME="0.0.0.0" # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the run time. # ENV NEXT_TELEMETRY_DISABLED=1 # Copy production assets COPY --from=builder --chown=node:node /app/public ./public # Set the correct permission for prerender cache RUN mkdir .next RUN chown node:node .next # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing COPY --from=builder --chown=node:node /app/.next/standalone ./ COPY --from=builder --chown=node:node /app/.next/static ./.next/static # If you want to persist the fetch cache generated during the build so that # cached responses are available immediately on startup, uncomment this line: # COPY --from=builder --chown=node:node /app/.next/cache ./.next/cache # Switch to non-root user for security best practices USER node # Expose port 3000 to allow HTTP traffic EXPOSE 3000 # Start Next.js standalone server CMD ["node", "server.js"]
Crea un Dockerfile multi-etapa listo para producción. Reemplaza el Dockerfile generado con el siguiente (utiliza node):
# ============================================
# Stage 1: Dependencies Installation Stage
# ============================================
ARG NODE_VERSION=24.14.0-slim
FROM node:${NODE_VERSION} AS dependencies
# Set working directory
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
# Install project dependencies with frozen lockfile for reproducible builds
RUN --mount=type=cache,target=/root/.npm \
--mount=type=cache,target=/usr/local/share/.cache/yarn \
--mount=type=cache,target=/root/.local/share/pnpm/store \
if [ -f package-lock.json ]; then \
npm ci --no-audit --no-fund; \
elif [ -f yarn.lock ]; then \
corepack enable yarn && yarn install --frozen-lockfile --production=false; \
elif [ -f pnpm-lock.yaml ]; then \
corepack enable pnpm && pnpm install --frozen-lockfile; \
else \
echo "No lockfile found." && exit 1; \
fi
# ============================================
# Stage 2: Build Next.js application in standalone mode
# ============================================
FROM node:${NODE_VERSION} AS builder
# Set working directory
WORKDIR /app
# Copy project dependencies from dependencies stage
COPY --from=dependencies /app/node_modules ./node_modules
# Copy application source code
COPY . .
ENV NODE_ENV=production
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1
# Build Next.js application
# If you want to speed up Docker rebuilds, you can cache the build artifacts
# by adding: --mount=type=cache,target=/app/.next/cache
# This caches the .next/cache directory across builds, but it also prevents
# .next/cache/fetch-cache from being included in the final image, meaning
# cached fetch responses from the build won't be available at runtime.
RUN if [ -f package-lock.json ]; then \
npm run build; \
elif [ -f yarn.lock ]; then \
corepack enable yarn && yarn build; \
elif [ -f pnpm-lock.yaml ]; then \
corepack enable pnpm && pnpm build; \
else \
echo "No lockfile found." && exit 1; \
fi
# ============================================
# Stage 3: Run Next.js application
# ============================================
FROM node:${NODE_VERSION} AS runner
# Set working directory
WORKDIR /app
# Set production environment variables
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the run time.
# ENV NEXT_TELEMETRY_DISABLED=1
# Copy production assets
COPY --from=builder --chown=node:node /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown node:node .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=node:node /app/.next/standalone ./
COPY --from=builder --chown=node:node /app/.next/static ./.next/static
# If you want to persist the fetch cache generated during the build so that
# cached responses are available immediately on startup, uncomment this line:
# COPY --from=builder --chown=node:node /app/.next/cache ./.next/cache
# Switch to non-root user for security best practices
USER node
# Expose port 3000 to allow HTTP traffic
EXPOSE 3000
# Start Next.js standalone server
CMD ["node", "server.js"]NoteEste Dockerfile utiliza tres etapas: dependencies (dependencias), builder (constructor) y runner (ejecutor). La imagen final ejecuta
node server.jsy escucha en el puerto 3000.
2.2 Next.js con salida export
La salida export (output: "export") hace que Next.js compile un sitio completamente estático durante el tiempo de construcción. Genera HTML, CSS y JavaScript dentro de un directorio out que puede ser servido por cualquier servidor estático o CDN—sin necesidad de un servidor Node.js en tiempo de ejecución. Utiliza esto cuando no necesites renderizado en el lado del servidor o rutas de API. Para obtener más detalles, consulta la documentación de configuración de salida de Next.js.
Configura Next.js — Abre next.config.ts en la raíz de tu proyecto y agrega el siguiente código:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "export",
trailingSlash: true,
images: {
unoptimized: true,
},
};
export default nextConfig;Elige una Imagen Endurecida de Docker o la Imagen Oficial de Docker, luego reemplaza tu Dockerfile con el contenido de la pestaña seleccionada a continuación.
Las Docker Hardened Images (DHIs) están disponibles para Node.js y NGINX en el catálogo de Docker Hardened Images. Para más información, consulta la guía de inicio rápido de DHI.
Inicia sesión en el registro de DHI:
$ docker login dhi.ioDescarga la DHI de Node.js (consulta el catálogo para ver las versiones disponibles):
$ docker pull dhi.io/node:24-alpine3.22-devDescarga la DHI de Nginx (consulta el catálogo para ver las versiones disponibles):
$ docker pull dhi.io/nginx:1.28.0-alpine3.21-devReemplaza el Dockerfile generado con el siguiente. Las instrucciones
FROMutilizan Docker Hardened Images:dhi.io/node:24-alpine3.22-devydhi.io/nginx:1.28.0-alpine3.21-dev. Consulta el catálogo de Docker Hardened Images para obtener las últimas versiones y actualiza las etiquetas de la imagen según sea necesario para la seguridad y compatibilidad.# ============================================ # Stage 1: Dependencies Installation Stage # ============================================ # IMPORTANT: Docker Hardened Image (DHI) Version Maintenance # This Dockerfile uses dhi.io/node and dhi.io/nginx. Regularly validate and update to the latest DHI versions in the catalog for security and compatibility. FROM dhi.io/node:24-alpine3.22-dev AS dependencies # Set the working directory WORKDIR /app # Copy package-related files first to leverage Docker's caching mechanism COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ # Install project dependencies with frozen lockfile for reproducible builds RUN --mount=type=cache,target=/root/.npm \ --mount=type=cache,target=/usr/local/share/.cache/yarn \ --mount=type=cache,target=/root/.local/share/pnpm/store \ if [ -f package-lock.json ]; then \ npm ci --no-audit --no-fund; \ elif [ -f yarn.lock ]; then \ corepack enable yarn && yarn install --frozen-lockfile --production=false; \ elif [ -f pnpm-lock.yaml ]; then \ corepack enable pnpm && pnpm install --frozen-lockfile; \ else \ echo "No lockfile found." && exit 1; \ fi # ============================================ # Stage 2: Build Next.js Application # ============================================ FROM dhi.io/node:24-alpine3.22-dev AS builder # Set the working directory WORKDIR /app # Copy project dependencies from dependencies stage COPY --from=dependencies /app/node_modules ./node_modules # Copy application source code COPY . . ENV NODE_ENV=production # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the build. # ENV NEXT_TELEMETRY_DISABLED=1 # Build Next.js application RUN --mount=type=cache,target=/app/.next/cache \ if [ -f package-lock.json ]; then \ npm run build; \ elif [ -f yarn.lock ]; then \ corepack enable yarn && yarn build; \ elif [ -f pnpm-lock.yaml ]; then \ corepack enable pnpm && pnpm build; \ else \ echo "No lockfile found." && exit 1; \ fi # ========================================= # Stage 3: Serve Static Files with Nginx # ========================================= FROM dhi.io/nginx:1.28.0-alpine3.21-dev AS runner # Set the working directory WORKDIR /app # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the run time. # ENV NEXT_TELEMETRY_DISABLED=1 # Copy custom Nginx config COPY nginx.conf /etc/nginx/nginx.conf # Copy the static build output from the build stage to Nginx's default HTML serving directory COPY --chown=nginx:nginx --from=builder /app/out /usr/share/nginx/html # Non-root user for security best practices USER nginx # Expose port 8080 to allow HTTP traffic EXPOSE 8080 # Start Nginx directly with custom config ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"] CMD ["-g", "daemon off;"]
Crea un Dockerfile multi-etapa listo para producción. Reemplaza el Dockerfile generado con el siguiente (utiliza node y nginxinc/nginx-unprivileged):
# ============================================
# Stage 1: Dependencies Installation Stage
# ============================================
ARG NODE_VERSION=24.14.0-slim
ARG NGINXINC_IMAGE_TAG=alpine3.22
FROM node:${NODE_VERSION} AS dependencies
# Set the working directory
WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
# Install project dependencies with frozen lockfile for reproducible builds
RUN --mount=type=cache,target=/root/.npm \
--mount=type=cache,target=/usr/local/share/.cache/yarn \
--mount=type=cache,target=/root/.local/share/pnpm/store \
if [ -f package-lock.json ]; then \
npm ci --no-audit --no-fund; \
elif [ -f yarn.lock ]; then \
corepack enable yarn && yarn install --frozen-lockfile --production=false; \
elif [ -f pnpm-lock.yaml ]; then \
corepack enable pnpm && pnpm install --frozen-lockfile; \
else \
echo "No lockfile found." && exit 1; \
fi
# ============================================
# Stage 2: Build Next.js Application
# ============================================
FROM node:${NODE_VERSION} AS builder
# Set the working directory
WORKDIR /app
# Copy project dependencies from dependencies stage
COPY --from=dependencies /app/node_modules ./node_modules
# Copy application source code
COPY . .
ENV NODE_ENV=production
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1
# Build Next.js application
RUN --mount=type=cache,target=/app/.next/cache \
if [ -f package-lock.json ]; then \
npm run build; \
elif [ -f yarn.lock ]; then \
corepack enable yarn && yarn build; \
elif [ -f pnpm-lock.yaml ]; then \
corepack enable pnpm && pnpm build; \
else \
echo "No lockfile found." && exit 1; \
fi
# =========================================
# Stage 3: Serve Static Files with Nginx
# =========================================
FROM nginxinc/nginx-unprivileged:${NGINXINC_IMAGE_TAG} AS runner
# Set the working directory
WORKDIR /app
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the run time.
# ENV NEXT_TELEMETRY_DISABLED=1
# Copy custom Nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy the static build output from the build stage to Nginx's default HTML serving directory
COPY --from=builder /app/out /usr/share/nginx/html
# Non-root user for security best practices
USER nginx
# Expose port 8080 to allow HTTP traffic
EXPOSE 8080
# Start Nginx directly with custom config
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
CMD ["-g", "daemon off;"]NoteUsamos nginx-unprivileged en lugar de la imagen estándar de NGINX para ejecutar como un usuario sin privilegios (no-root), siguiendo las mejores prácticas de seguridad.
Crea
nginx.conf(requerido solo para la salida export) — Crea un archivo llamadonginx.confen la raíz de tu proyecto:# Minimal Nginx config for static Next.js app worker_processes 1; # Store PID in /tmp (always writable) pid /tmp/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; # Disable logging to avoid permission issues access_log off; error_log /dev/stderr; # Optimize static file serving sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; # Gzip compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; gzip_min_length 256; server { listen 8080; server_name localhost; # Serve static files root /usr/share/nginx/html; index index.html; # Handle Next.js static export routing # See: https://nextjs.org/docs/app/guides/static-exports#deploying location / { try_files $uri $uri.html $uri/ =404; } # This is necessary when `trailingSlash: false` (default). # You can omit this when `trailingSlash: true` in next.config. # Handles nested routes like /blog/post -> /blog/post.html location ~ ^/(.+)/$ { rewrite ^/(.+)/$ /$1.html break; } # Serve Next.js static assets location ~ ^/_next/ { try_files $uri =404; expires 1y; add_header Cache-Control "public, immutable"; } # Optional 404 handling error_page 404 /404.html; location = /404.html { internal; } } }NoteExport utiliza el puerto 8080. Para más detalles, consulta la documentación de configuración de salida de Next.js y la documentación de NGINX.
Paso 3: Configurar el archivo .dockerignore
El archivo .dockerignore le indica a Docker qué archivos y carpetas excluir al construir la imagen.
NoteEsto ayuda a:
- Reducir el tamaño de la imagen
- Acelerar el proceso de construcción
- Evitar que archivos sensibles o innecesarios (como
.env,.gitonode_modules) se agreguen a la imagen final.Para aprender más, visita la referencia de .dockerignore.
Copia y reemplaza el contenido de tu .dockerignore existente con la siguiente configuración:
# Dependencies (installed inside the image, never copy from host)
node_modules/
.pnp/
.pnp.js
.pnpm-store/
# Next.js build output (generated during the image build)
.next/
out/
dist/
build/
.vercel/
# Testing (not needed in the production image)
coverage/
.nyc_output/
__tests__/
__mocks__/
jest/
cypress/
playwright-report/
test-results/
.vitest/
# Environment files (avoid leaking secrets into the build context)
.env
.env*
.env.local
.env.development.local
.env.test.local
.env.production.local
# Debug and log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
*.log
# IDE and editor files
.vscode/
.idea/
.cursor/
.cursorrules
.copilot/
*.swp
*.swo
*~
# Git
.git/
.gitignore
.gitattributes
# Docker files (reduce build context; not needed inside the image)
Dockerfile*
.dockerignore
docker-compose*.yml
compose*.yaml
# Documentation (not needed in the image)
*.md
docs/
# CI/CD (not needed in the image)
.github/
.gitlab-ci.yml
.travis.yml
.circleci/
Jenkinsfile
# TypeScript and build metadata
*.tsbuildinfo
# Cache and temporary directories
.cache/
.parcel-cache/
.eslintcache
.stylelintcache
.turbo/
.tmp/
.temp/
# Sensitive or dev-only config (optional; omit if your build needs these)
.pem
.editorconfig
.prettierrc*
.eslintrc*
.stylelintrc*
.babelrc*
*.iml
# OS-specific files
.DS_Store
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Desktop.iniPaso 4: Construir la imagen de la aplicación Next.js
Con tu configuración personalizada en su lugar, ahora estás listo para construir la imagen de Docker. Usa el Dockerfile que elegiste en el Paso 3 (standalone o export).
La configuración incluye:
- Construcciones multi-etapa para optimizar el tamaño de la imagen.
- Standalone: servidor Node.js en el puerto 3000; Export: NGINX sirviendo archivos estáticos en el puerto 8080.
- Usuario no-root para mayor seguridad.
- Permisos y propiedad de archivos correctos.
Después de completar los pasos anteriores, tu directorio de proyecto debería contener al menos los siguientes archivos (la opción export también requiere nginx.conf):
├── docker-nextjs-sample/
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── next.config.ts
│ └── README.Docker.mdAhora que tu Dockerfile está configurado, puedes construir la imagen de Docker para tu aplicación Next.js.
NoteEl comando
docker buildempaqueta tu aplicación en una imagen utilizando las instrucciones del Dockerfile. Incluye todos los archivos necesarios del directorio actual (llamado el contexto de construcción).
Ejecuta el siguiente comando desde la raíz de tu proyecto:
$ docker build --tag nextjs-sample .
Qué hace este comando:
- Utiliza el Dockerfile en el directorio actual (
.). - Empaqueta la aplicación y sus dependencias en una imagen de Docker.
- Etiqueta la imagen como
nextjs-samplepara que puedas hacer referencia a ella más tarde.
Paso 5: Ver imágenes locales
Después de construir tu imagen de Docker, puedes verificar qué imágenes están disponibles en tu máquina local usando la CLI de Docker o Docker Desktop. Como ya estás trabajando en la terminal, usemos la CLI de Docker.
Para listar todas las imágenes de Docker disponibles localmente, ejecuta el siguiente comando:
$ docker images
Salida de ejemplo:
REPOSITORY TAG IMAGE ID CREATED SIZE
nextjs-sample latest 8c5fc80f098e 14 seconds ago 130MBEsta salida proporciona detalles clave sobre tus imágenes:
- Repository – El nombre asignado a la imagen.
- Tag – Una etiqueta de versión que ayuda a identificar diferentes construcciones (por ejemplo,
latest). - Image ID – Un identificador único para la imagen.
- Created – La marca de tiempo que indica cuándo se construyó la imagen.
- Size – El espacio total en disco utilizado por la imagen.
Si la construcción fue exitosa, deberías ver la imagen nextjs-sample en la lista.
Ejecutar la aplicación contenerizada
En el paso anterior, creaste un Dockerfile para tu aplicación Next.js y construiste una imagen de Docker usando el comando docker build. Ahora es el momento de ejecutar esa imagen en un contenedor y verificar que tu aplicación funcione como se espera.
Ejecuta el siguiente comando en una terminal. Usa el puerto que coincida con tu configuración: standalone usa el puerto 3000, export usa el puerto 8080.
$ docker run -p 3000:3000 nextjs-sample
Para la salida export, usa el puerto 8080 en su lugar:
$ docker run -p 8080:8080 nextjs-sample
Abre un navegador y visita la aplicación: http://localhost:3000 para standalone o http://localhost:8080 for export. Deberías ver tu aplicación web de Next.js.
Presiona ctrl+c en la terminal para detener tu aplicación.
Ejecutar la aplicación en segundo plano
Puedes ejecutar la aplicación desconectada (detached) de la terminal agregando la opción -d y --name para darle un nombre al contenedor para que puedas detenerlo más tarde:
$ docker run -d -p 3000:3000 --name nextjs-app nextjs-sample
Para la salida export, usa el puerto 8080:
$ docker run -d -p 8080:8080 --name nextjs-app nextjs-sample
Abre un navegador y visita la aplicación: http://localhost:3000 para standalone o http://localhost:8080 para export. Deberías ver tu aplicación web.
Para confirmar que el contenedor se está ejecutando, usa el comando docker ps:
$ docker ps
Esto listará todos los contenedores activos junto con sus puertos, nombres y estado. Busca un contenedor que exponga el puerto 3000 (standalone) o 8080 (export).
Salida de ejemplo:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f49b74736a9d nextjs-sample "node server.js" About a minute ago Up About a minute 0.0.0.0:3000->3000/tcp nextjs-appPara detener la aplicación, ejecuta:
$ docker stop nextjs-app
NotePara obtener más información sobre cómo ejecutar contenedores, consulta la referencia de CLI de
docker runy la referencia de CLI dedocker stop.
Resumen
En esta guía, aprendiste a contenerizar, construir y ejecutar una aplicación Next.js usando Docker. Siguiendo las mejores prácticas, creaste una configuración segura, optimizada y lista para producción.
Lo que lograste:
- Inicializaste tu proyecto usando
docker initpara andamiar archivos esenciales de configuración de Docker. - Configuraste Next.js tanto para salida standalone (servidor Node.js) como para salida export (archivos estáticos con NGINX).
- Agregaste un Dockerfile multi-etapa para el enfoque elegido: standalone (puerto 3000) o export (puerto 8080, con
nginx.conf). - Reemplazaste el archivo
.dockerignorepredeterminado para excluir archivos innecesarios y mantener la imagen limpia y eficiente. - Construiste tu imagen de Docker usando
docker build. - Ejecutaste el contenedor usando
docker runcon el nombre de imagennextjs-sample, tanto en primer plano como en modo desconectado (detached). - Verificaste que la aplicación se estuviera ejecutando visitando http://localhost:3000 (standalone) o http://localhost:8080 (export).
- Aprendiste a detener la aplicación contenerizada usando
docker stop nextjs-app.
Ahora tienes una aplicación Next.js completamente contenerizada, ejecutándose en un contenedor Docker y lista para ser desplegada en cualquier entorno con confianza y consistencia.
Recursos relacionados
Explora las referencias oficiales y las mejores prácticas para perfeccionar tu flujo de trabajo con Docker:
- Construcciones multi-etapa – Aprende cómo separar las etapas de construcción y de tiempo de ejecución.
- Mejores prácticas para escribir Dockerfiles – Escribe Dockerfiles eficientes, fáciles de mantener y seguros.
- Contexto de construcción en Docker – Aprende cómo el contexto afecta la construcción de imágenes.
- Configuración de salida de Next.js – Aprende sobre la optimización de producción de Next.js (standalone y export).
- Next.js con Docker (standalone) – Ejemplo oficial de Next.js: salida standalone con Node.js.
- Next.js con Docker (export) – Ejemplo oficial de Next.js: exportación estática con Nginx o serve.
- Referencia de CLI de
docker init– Andaia recursos de Docker automáticamente. - Referencia de CLI de
docker build– Construye imágenes de Docker a partir de un Dockerfile. - Referencia de CLI de
docker images– Gestiona e inspecciona imágenes de Docker locales. - Referencia de CLI de
docker run– Ejecuta un comando en un nuevo contenedor. - Referencia de CLI de
docker stop– Detiene uno o más contenedores en ejecución.
Próximos pasos
Con tu aplicación Next.js ahora contenerizada, estás listo para pasar al siguiente paso.
En la siguiente sección, aprenderás cómo desarrollar tu aplicación usando contenedores Docker, lo que permite un entorno de desarrollo consistente, aislado y reproducible en cualquier máquina.