Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Implementa una aplicación Next.js 15+ App Router con modo de salida standalone, contenedores Docker, funciones de edge runtime y optimizaciones específicas de plataforma.
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
};
export default nextConfig;# Compila la aplicación
npm run build
# La salida standalone está en .next/standalone
# Copia los assets estáticos y públicos
cp -r .next/static .next/standalone/.next/static
cp -r public .next/standalone/public
# Ejecuta el servidor standalone
node .next/standalone/server.js# Dockerfile
FROM node:20-alpine AS base
# Instala las dependencias
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
# Compila la aplicación
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# Imagen de producción
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /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"
CMD ["node", "server.js"]# docker-compose.yml
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- AUTH_SECRET=your-secret-here
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:// app/api/geo/route.ts
import { NextRequest, NextResponse } from "next/server";
export const runtime = "edge";
export async function GET(request: NextRequest) {
return NextResponse.json({
city: request.geo?.city ?? "unknown",
country: request.geo?.country ?? "unknown",
region: request.geo?.region ?? "unknown",
});
}// middleware.ts
import { NextRequest, NextResponse } from "next/server";
// El middleware siempre se ejecuta en el edge
export function middleware(request: NextRequest) {
const country = request.geo?.country ?? "US";
const response = NextResponse.next();
response.headers.set("x-user-country", country);
return response;
}// package.json
{
"scripts": {
"build": "next build",
"analyze": "ANALYZE=true next build",
"start": "next start",
"start:standalone": "node .next/standalone/server.js"
}
}// next.config.ts (con analizador de paquetes)
import type { NextConfig } from "next";
import withBundleAnalyzer from "@next/bundle-analyzer";
const nextConfig: NextConfig = {
output: "standalone",
};
export default withBundleAnalyzer({
enabled: process.env.ANALYZE === "true",
})(nextConfig);output: "standalone" produce una compilación autónoma que incluye solo los archivos node_modules necesarios. La salida en .next/standalone puede ejecutarse con solo node server.js, sin necesidad del directorio node_modules completo..next/static) y public/ no se incluyen en la salida standalone. Deben copiarse por separado o servirse desde un CDN.fs, Buffer o módulos nativos.HOSTNAME="0.0.0.0" es necesario en Docker para aceptar conexiones desde fuera del contenedor. Sin él, el servidor se vincula a 127.0.0.1 y es inaccesible.Exportación Estática (Sin Servidor):
// next.config.ts
const nextConfig: NextConfig = {
output: "export",
};Esto genera un sitio completamente estático en el directorio out/. No se requiere servidor Node.js. Limitaciones: sin Server Components en el tiempo de solicitud, sin rutas API, sin middleware, sin ISR.
Despliegue en Vercel:
# Instala la CLI de Vercel
npm i -g vercel
# Despliega (detección automática de Next.js)
vercel
# Despliega en producción
vercel --prodVercel maneja automáticamente la salida standalone, las funciones edge y la distribución de CDN. No se necesita Dockerfile.
Punto Final de Verificación de Salud Personalizado:
// app/api/health/route.ts
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({
status: "ok",
timestamp: new Date().toISOString(),
version: process.env.APP_VERSION ?? "unknown",
});
}request.geo está tipado como { city?: string; country?: string; region?: string; latitude?: string; longitude?: string } | undefined. Solo se completa en despliegues edge (Vercel, Cloudflare).runtime debe ser un literal de string ("edge" o "nodejs"). No puede ser una variable.public/ o .next/static/. Debes copiar estos directorios en la salida standalone o servirlos desde un CDN.fs, path, child_process, crypto (usa globalThis.crypto), y la mayoría de módulos nativos no están disponibles. Consulta la referencia de API de Edge Runtime de Next.js.docker run -e KEY=value) y accede a ellas a través de process.env en el código del servidor. Las variables NEXT_PUBLIC_ siempre son solo de tiempo de compilación./_next/static/ y /public/.output: "export" desactiva todas las características del servidor. Sin Server Components en el tiempo de solicitud, sin Route Handlers, sin middleware, sin ISR. Solo úsalo para sitios completamente estáticos.sharp a tus dependencias: npm install sharp.| Enfoque | Ventajas | Desventajas |
|---|---|---|
| Vercel | Cero configuración, edge-nativo, CDN automático | Bloqueo de proveedor, costo en escala |
| Docker + standalone | Portátil, cualquier proveedor en la nube | Configuración de infraestructura manual, sin edge por defecto |
Exportación estática (output: "export") | Sin servidor, hospedaje barato (S3, Cloudflare) | Sin características del servidor |
| AWS Amplify | Administrado, admite SSR | Configuración de edge limitada, específico de AWS |
| Cloudflare Pages | Primero en edge, rápido, nivel gratuito generoso | Soporte limitado de API de Node.js |
| Railway o Fly.io | Basado en Docker, DX simple | Ecosistema más pequeño |
node_modules necesarios.node server.js, sin el directorio node_modules completo.127.0.0.1 (solo localhost).127.0.0.1 es inaccesible desde fuera del contenedor.HOSTNAME="0.0.0.0" hace que el servidor acepte conexiones desde cualquier interfaz de red.fs, path, child_process o Buffer.globalThis.crypto en lugar del módulo crypto de Node.js.NEXT_PUBLIC_ se reemplazan estáticamente en el tiempo next build.NEXT_PUBLIC_.out/ sin servidor necesario.npm install sharp o las imágenes no se optimizarán.export const runtime = "edge";
// o
export const runtime = "nodejs";"edge" | "nodejs".deps) instala solo las dependencias de producción.builder) copia deps y compila la aplicación.runner) copia solo la salida standalone, reduciendo el tamaño de la imagen final.server.js standalone es un servidor Node.js mínimo enfocado en SSR.export async function GET(request: NextRequest) {
const city = request.geo?.city ?? "unknown";
}request.geo solo se completa en despliegues edge (Vercel, Cloudflare).undefined en desarrollo local y despliegues de Node.js no-edge.{ status: "ok" } con metadatos opcionales.Revisado por Chris St. John·Última actualización: 7 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥