Despliegue moderno de Next.js: GitHub Actions, Docker y cero tiempo de inactividad
Publicado el 02.03.2026
Si todavía haces next build directamente en el servidor de producción — tu servidor realmente sufre. CPU al máximo, OOM-kill, errores 502 y largos tiempos de inactividad — es un clásico que ya es hora de terminar.
En 2026, el estándar de la industria es la construcción separada:
- Construimos una imagen standalone mínima en la nube con GitHub Actions.
- La empujamos a GHCR (GitHub Container Registry).
- En el servidor solo hacemos pull + reinicio atómico.
Capítulo 1. Dockerfile ideal (multietapa + standalone)
Todo el secreto de una imagen pequeña y rápida está en el modo standalone. Next.js calcula por sí mismo qué archivos y partes de node_modules son realmente necesarios para que funcione el servidor, y copia solo esos.
# syntax=docker/dockerfile:1
# ETAPA 1 — Dependencias
FROM node:24-alpine AS deps
WORKDIR /app
COPY package.json yarn.lock* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else npm ci; \
fi
# ETAPA 2 — Compilación
FROM node:24-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# ETAPA 3 — Imagen de producción (Runner)
FROM node:24-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Seguridad ante todo: no ejecutar como root
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 nextjs
# Copiamos solo los artefactos de la compilación standalone
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Comprobación de salud del contenedor
HEALTHCHECK --interval=15s --timeout=3s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
CMD ["node", "server.js"]
¿Por qué es genial?
- Tamaño: La imagen pesa ~200 MB frente a 1.5 GB de la habitual.
- Seguridad: Usar un usuario
non-root(nextjs) protege el sistema anfitrión en caso de compromiso del contenedor. - Healthcheck: Docker detectará si la aplicación se ‘colgó’ al iniciar y no enviará tráfico a ella.
Capítulo 2. Análisis del workflow de GitHub Actions
Tu pipeline está dividido en dos etapas (jobs): la construcción en la nube y el despliegue en tu “hardware”.
1. Preparación y build
- name: Docker meta & tags
id: prepare
run: |
IMAGE_REPO="ghcr.io/${GITHUB_REPOSITORY,,}"
SHORT_SHA="${GITHUB_SHA::8}"
echo "image_repo=$IMAGE_REPO" >> $GITHUB_OUTPUT
echo "image_tag=sha-$SHORT_SHA" >> $GITHUB_OUTPUT
Importante: La sintaxis ${GITHUB_REPOSITORY,,} convierte el nombre del repositorio a minúsculas. Los registros de Docker no aceptan mayúsculas, y en GitHub a menudo las hay.
2. Caché de la compilación
cache-from: type=gha
cache-to: type=gha,mode=max
Usamos el caché nativo de GitHub Actions. Si no has cambiado package.json, la etapa de instalación de dependencias se omitirá y el build durará 1–2 minutos en lugar de 10.
3. Despliegue inteligente (bucle de healthcheck)
El punto más importante — no solo decimos al servidor “actualízate”, comprobamos si la aplicación sobrevivió.
for i in {1..60}; do
STATUS=$(docker inspect --format='{{json .State.Health.Status}}' nextjs 2>/dev/null || echo '"not-found"')
if [[ $STATUS == '"healthy"' || $STATUS == '"no-healthcheck"' ]]; then
HEALTHY=1
break
fi
sleep 2
done
Si Next.js se cae por un error en las variables de entorno, el script lo detectará, no actualizará el proxy (Caddy/Nginx) y terminará la acción con error. Tu sitio antiguo seguirá funcionando y recibirás una notificación del problema.
Capítulo 3. Variables en tiempo de ejecución vs en tiempo de compilación
Estas son las trampas en las que casi todos caen.
NEXT_PUBLIC_(Build-time): Estas variables se “incrustan” en el bundle JS durante el comandonext build. Si las cambias en el servidor en.env, no cambiará nada. Debes pasarlas en GitHub Actions comobuild-args.Secretos (Runtime):
DATABASE_URL,JWT_SECRET. No se deben meter en la imagen Docker. Se inyectan en el momento de arrancar el contenedor mediantedocker-compose.
Consejo: Si es posible, haz que la URL de la API también sea una variable en tiempo de ejecución mediante proxy o scripts de configuración especiales, para que la misma imagen pueda desplegarse tanto en staging como en producción sin reconstrucción.
Reseñas relacionadas
Hubo varios problemas, tanto en la parte técnica como en la comprensión general. Mijaíl respondió rápido a la solicitud, ayudó a aclarar las cosas y resolvió los problemas técnicos; por ello, muchas gracias. Estoy satisfecho con el resultado.
abazawolf · Configuración de VPS, configuración del servidor
18.02.2026 · ⭐ 5/5
Hubo varios problemas relacionados tanto con la parte técnica como con la comprensión en general. Mijaíl respondió rápidamente a la solicitud, ayudó a aclarar las cosas y resolvió los problemas técnicos, por lo que le doy las gracias por ello. Estoy satisfecho con el resultado.
Todo se hizo de manera rápida y precisa. Lo recomiendo.
Akelebra · Configuración de VPS, configuración del servidor
17.01.2026 · ⭐ 5/5
Todo se hizo rápido y con precisión. Lo recomiendo.
Todo salió bien, el profesional respondió rápidamente a las preguntas y ayudó a resolver el problema. ¡Gracias!
visupSTUDIO · Configuración de VPS, configuración del servidor
16.12.2025 · ⭐ 5/5
Todo fue bien, el profesional respondió rápidamente a las preguntas y ayudó a resolver el problema. ¡Gracias!
Lo hicieron todo con rapidez. Seguiremos acudiendo. ¡Lo recomiendo!
rotant · Configuración de VPS, configuración del servidor
10.12.2025 · ⭐ 5/5
Todo lo hicieron con rapidez. Seguiremos acudiendo. ¡Lo recomiendo!
Hicieron todo rápidamente. Mijaíl siempre está disponible. Seguiremos recurriendo a él.
samstiray · Configuración de VPS, configuración del servidor
10.12.2025 · ⭐ 5/5
Todo se hizo con rapidez. Михаил siempre está en contacto. Seguiremos recurriendo a él
¡Mijaíl es un profesional! Ya no es la primera vez que lo demuestra en la práctica.
Vadim_U · Configuración de VPS, configuración del servidor
Cliente acostumbrado03.12.2025 · ⭐ 5/5
Михаил, ¡un profesional! Ya lo ha demostrado en la práctica más de una vez.