← volver al blog

Node v12 → v22 en producción sin romper todo: estrategia y lecciones

El plan que usamos para migrar 15+ servicios de Node 12 a Node 22 en Kubernetes sin downtime.

Contexto

15 microservicios en Node 12 (sí, EOL hace años). Kubernetes en GKE. La deuda técnica ya no era negociable — dependencias sin parches de seguridad, features de lenguaje atrasados 5 años.

La estrategia: saltos incrementales

No hicimos 12 → 22 directo. Fuimos 12 → 18 → 22, porque:

  • Node 18 fue el primer LTS con cambios breaking manejables desde v12
  • Node 22 tiene require(esm) experimental, que necesitábamos para una migración gradual de CJS → ESM
# Multi-stage para testear en ambas versiones durante la transición
FROM node:18-alpine AS build-18
COPY . .
RUN npm ci && npm test

FROM node:22-alpine AS build-22
COPY . .
RUN npm ci && npm test

Los breaking changes que más dolieron

1. dns.lookup cambió de orden

// Node 12: resolvía IPv4 primero por defecto
// Node 18+: respeta el orden del OS
// Fix: ser explícito
dns.lookup(hostname, { family: 4 }, callback);

2. OpenSSL 3.0

# Error que aparecía en todas partes
Error: error:0308010C:digital envelope routines::unsupported

No usamos --openssl-legacy-provider. Actualizamos las dependencias que usaban algoritmos legacy.

3. fetch global

Pudimos eliminar node-fetch de 12 servicios. Menos dependencias, menos surface area.

Rollout

Usamos canary deployments en Kubernetes — 10% del tráfico al pod con Node 22, monitoreando latencia y error rate en Datadog durante 48h antes de ir full.

# deployment canary
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: api
          image: registry/service:node22-canary

Resultado

  • Zero downtime en la migración
  • -23% memory footprint promedio (V8 mejoró bastante)
  • Todas las deps actualizadas a versiones con soporte