Migración de WordPress a Next.js: Financial SaaS Ahorra $420K ARR
Tu oficial de cumplimiento envía un correo electrónico a las 21:47: las cargas de página alcanzan 4.2 segundos, y eso es una exposición regulatoria. Tu CFO reenvía la renovación anual de CMS de $420K una hora después con una palabra: '¿Por qué?' Ambos hilos apuntan al mismo monolito de WordPress — un sitio de marketing, portal de clientes y centro de documentación unidos por 19 complementos premium y una pila de licencias que cuesta más que dos ingenieros. El financial SaaS de Serie C detrás de estos correos necesitaba una migración headless a Next.js que eliminara el tiempo de inactividad, porque en fintech, cada segundo sin conexión desencadena el escrutinio de los reguladores y llamadas enfadadas de clientes empresariales. También necesitaban que la estructura de costos tuviera sentido antes de la próxima reunión de la junta. Construimos la migración en 90 días y redujimos el gasto de infraestructura en un 73% mientras triplicamos la velocidad de página — pero la parte más difícil no fue el código.
Esta es la historia completa de cómo lo logramos.
Tabla de contenidos
- El punto de partida: Un monolito de WordPress bajo presión
- Por qué Next.js headless fue la decisión correcta
- La arquitectura de migración
- Estrategia de cero tiempo de inactividad: la ejecución en paralelo
- Resultados de rendimiento: 3x más rápido y más
- Desglose de ahorros de $420K en licencias
- Inmersión técnica profunda: detalles clave de implementación
- Lecciones aprendidas de la manera difícil
- Cronograma y estructura del equipo
- FAQ

El punto de partida: Un monolito de WordPress bajo presión
Déjame pintar el cuadro. Esta empresa — la llamaremos FinEdge (NDA, entiende) — tenía aproximadamente 12,000 páginas de contenido en tres propiedades web distintas:
- Sitio de marketing — Páginas de producto, landing pages, blog con más de 2,400 posts
- Portal de clientes — Paneles de control de cuenta, flujos de incorporación, gestión de documentos
- Centro de documentación — Documentos de API, guías de cumplimiento, tutoriales de integración
Los tres funcionaban en una única instalación multisitio de WordPress alojada en el nivel empresarial de WP Engine. La situación de complementos era... algo. Ejecutaban 47 complementos activos, incluyendo WPGraphQL, Advanced Custom Fields Pro, Yoast SEO Premium, WP Rocket, Gravity Forms, y un complemento personalizado que su agencia anterior construyó que manejaba el registro de cumplimiento SOC 2 para cambios de contenido.
Los verdaderos puntos de dolor:
- Tiempos de carga de página promediando 4.2 segundos en móvil (datos de Google CrUX)
- Core Web Vitals fallando en el 68% de las páginas — LCP fue brutal con 5.1s en la mediana
- $420K/año en licencias entre hosting empresarial de WP Engine, complementos premium, un WAF, CDN, y un entorno de staging separado
- Los editores de contenido esperan 8-12 segundos para que el administrador de WordPress responda durante las horas pico
- Parches de seguridad requerían tiempo dedicado de DevOps cada dos semanas — los reguladores de servicios financieros no bromean
- Sin implementaciones de vista previa — el equipo de contenido tenía que enviar al staging y esperar 4 minutos para la invalidación de caché
Nuestro VP de Ingeniería nos dijo durante la llamada de descubrimiento: "Estamos gastando más en la infraestructura de nuestro sitio web que en dos ingenieros senior. Y aún es lento".
Por qué Next.js headless fue la decisión correcta
Evaluamos varias opciones durante la fase de arquitectura. Aquí está lo que estaba en la mesa:
| Opción | Ventajas | Desventajas | Costo anual estimado |
|---|---|---|---|
| WordPress (optimizado) | Familiar para el equipo, sin migración necesaria | Aún lento, licencias sin cambios | $420K |
| Webflow Enterprise | Edición visual, despliegue rápido | Limitado para necesidades de portal/aplicación, bloqueo de proveedor | $180K |
| Next.js + Sanity | Increíblemente rápido, flexible, vista previa en tiempo real | Esfuerzo de migración, curva de aprendizaje del equipo | $38K |
| Next.js + Contentful | Fuertes características empresariales, buen DX | Los precios por usuario se escalan mal | $95K |
| Astro + Storyblok | Excelente para contenido estático, ligero | Menos maduro para necesidades de portal dinámico | $42K |
Nos decidimos por Next.js 14 (App Router) con Sanity como CMS headless. Aquí está por qué:
- El portal de FinEdge tenía rutas autenticadas dinámicas que necesitaban renderizado en el servidor. Next.js lo maneja nativamente con React Server Components.
- El lenguaje de consulta real en tiempo GROQ de Sanity dio a los editores de contenido una experiencia dramáticamente mejor que WordPress.
- El modelo de precios (plan Growth de Sanity a $99/mes + Vercel Pro) significó que los costos de infraestructura bajaron de $420K a aproximadamente $38K anuales.
- El equipo de ingeniería ya conocía React. La curva de aprendizaje para Next.js se midió en días, no en meses.
Consideramos seriamente Astro para el centro de documentación ya que es principalmente contenido estático, pero la simplicidad operativa de mantener todo en un framework ganó. Si el sitio de documentación hubiera sido un proyecto independiente, Astro habría sido la opción.
La arquitectura de migración
Aquí está la arquitectura de alto nivel que diseñamos:
┌─────────────────┐ ┌──────────────────┐
│ Sanity CMS │────▶│ Next.js on │
│ (Content) │ │ Vercel (Edge) │
└─────────────────┘ └──────────────────┘
│ │
│ ▼
│ ┌──────────────────┐
│ │ Cloudflare │
│ │ (DNS + WAF) │
│ └──────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ Media Pipeline │ │ End Users │
│ (Cloudinary) │ └──────────────────┘
└─────────────────┘
Los componentes clave:
Capa de contenido
- Sanity como CMS principal para contenido de marketing, posts de blog y documentación
- Esquemas Sanity personalizados que se asignaron a sus tipos de contenido existentes de WordPress
- Portable Text para contenido enriquecido (reemplazando los bloques Gutenberg de WordPress)
Capa de aplicación
- Next.js 14 con App Router, desplegado en el plan Pro de Vercel
- React Server Components para el sitio de marketing y documentación
- Componentes cliente solo donde la interactividad fue genuinamente necesaria (formularios, paneles, gráficos interactivos)
- Middleware para autenticación en rutas del portal, integrado con su configuración Auth0 existente
Capa de infraestructura
- Vercel para alojamiento y funciones edge
- Cloudflare para gestión de DNS y reglas WAF adicionales (requisito de cumplimiento de servicios financieros)
- Cloudinary para optimización y transformación de imágenes — reemplazó 3 complementos de imagen de WordPress

Estrategia de cero tiempo de inactividad: la ejecución en paralelo
Esta era la parte que me mantenía despierto por la noche. FinEdge no podía permitirse ni siquiera algunos minutos de tiempo de inactividad. Su portal de clientes procesa transacciones financieras, y cualquier interrupción desencadena informes de incidentes obligatorios a los reguladores.
Aquí está cómo lo hicimos:
Fase 1: Sincronización de contenido (Semanas 1-3)
Construimos una tubería de sincronización personalizada de WordPress a Sanity que se ejecutaba continuamente durante el período de migración:
// Versión simplificada de nuestro trabajador de sincronización WP-a-Sanity
import { createClient } from '@sanity/client'
import WPGraphQL from './wp-graphql-client'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID,
dataset: 'production',
token: process.env.SANITY_WRITE_TOKEN,
apiVersion: '2024-10-01',
useCdn: false,
})
async function syncPosts(since: string) {
const posts = await WPGraphQL.getModifiedPosts(since)
const transaction = sanity.transaction()
for (const post of posts) {
const sanityDoc = transformWPToSanity(post)
transaction.createOrReplace(sanityDoc)
}
await transaction.commit()
console.log(`Synced ${posts.length} posts`)
}
// Se ejecutó cada 5 minutos vía cron
Esto significaba que los editores de contenido podían seguir trabajando en WordPress durante toda la migración. Cada cambio que hicieron fue sincronizado automáticamente a Sanity dentro de 5 minutos.
Fase 2: Despliegue en paralelo (Semanas 4-8)
Desplegamos el sitio Next.js en un subdominio (next.finedge.com) e ejecutamos ambos sitios simultáneamente. Nuestro proceso de QA comparó cada página única:
- Pruebas de regresión visual con Playwright en más de 200 páginas críticas
- Comprobaciones de paridad SEO (etiquetas meta, datos estructurados, URLs canónicas, mapas del sitio)
- Benchmarks de rendimiento en cada plantilla de página
- Auditorías de accesibilidad (WCAG 2.1 AA — requerido para servicios financieros)
Fase 3: La transición (Semana 9)
El cambio real fue anticlimático — que es exactamente lo que quieres. Usamos el equilibrio de carga de Cloudflare para cambiar gradualmente el tráfico:
- Hora 0: 5% del tráfico a Next.js, 95% a WordPress
- Hora 2: 25% / 75% (monitoreando tasas de error, Core Web Vitals)
- Hora 6: 50% / 50%
- Hora 12: 90% / 10%
- Hora 24: 100% Next.js, WordPress en modo de solo lectura
- Semana 2: WordPress desmantelado
Cero errores. Cero tiempo de inactividad. Los paneles de monitoreo fueron aburridamente verdes.
Resultados de rendimiento: 3x más rápido y más
Aquí están los números reales, medidos 30 días después de la migración usando datos de Google CrUX y Vercel Analytics:
| Métrica | WordPress (Antes) | Next.js (Después) | Mejora |
|---|---|---|---|
| LCP (p75) | 5.1s | 1.2s | 4.25x más rápido |
| FID / INP (p75) | 280ms | 68ms | 4.1x más rápido |
| CLS (p75) | 0.18 | 0.02 | 9x mejor |
| TTFB (p75) | 1.8s | 0.12s | 15x más rápido |
| Rendimiento de Lighthouse | 34 | 96 | +62 puntos |
| Páginas aprobando CWV | 32% | 98% | +66% |
| Tiempo a interactivo | 6.8s | 1.4s | 4.9x más rápido |
El titular "3x más rápido" en realidad lo subestima. En la mayoría de las métricas, vimos mejoras de 4-5x. TTFB fue la estrella — bajando de 1.8 segundos a 120 milisegundos gracias a la Edge Network de Vercel e ISR (Incremental Static Regeneration).
El tráfico orgánico aumentó un 31% en los primeros 90 días posteriores a la migración. Su equipo de SEO atribuyó esto principalmente a mejoras de Core Web Vitals y tasas de rastreo más rápidas de Googlebot.
Desglose de ahorros de $420K en licencias
Hablemos de dinero. Aquí está exactamente dónde iban los $420K y qué los reemplazó:
| Elemento | Costo anual de WordPress | Costo anual de Next.js | Ahorros |
|---|---|---|---|
| Hosting empresarial de WP Engine | $150,000 | — | $150,000 |
| Vercel Pro (plan de equipo) | — | $2,400 | — |
| Licencias de complementos premium (47 complementos) | $28,000 | — | $28,000 |
| Plan Growth de Sanity | — | $1,188 | — |
| Cloudinary Pro | — | $2,388 | — |
| WAF empresarial (Sucuri) | $36,000 | — | $36,000 |
| Cloudflare Pro | — | $2,400 | — |
| Contrato personalizado de mantenimiento de WordPress | $96,000 | — | $96,000 |
| CDN (separado de WP Engine) | $24,000 | — | $24,000 |
| Hosting de entorno de staging | $18,000 | — | $18,000 |
| Auditorías de seguridad de WordPress (trimestral) | $48,000 | — | $48,000 |
| Tiempo del equipo de DevOps (FTE parcial) | $120,000 | $30,000 | $90,000 |
| Totales | $520,000 | $38,376 | $481,624 |
Los ahorros reales terminaron siendo más cercanos a $482K, no $420K. La estimación original de $420K de la fase de descubrimiento fue conservadora — inicialmente no contabilizamos la reducción en el tiempo de DevOps o la eliminación de auditorías de seguridad trimestrales (Vercel y Cloudflare manejan la mayoría de lo que esas auditorías cubrían).
La matemática del ROI es directa. Nuestro proyecto de migración costó a FinEdge aproximadamente $185K en honorarios de agencia durante el compromiso de 10 semanas. Esa inversión se pagó en menos de 5 meses.
Inmersión técnica profunda: detalles clave de implementación
Manejando 2,400 posts de blog con ISR
No generamos estáticamente todos los 2,400 posts de blog en el momento de la construcción. Eso habría hecho que los despliegues fueran dolorosamente lentos. En su lugar, usamos ISR con revalidación bajo demanda:
// app/blog/[slug]/page.tsx
import { sanityFetch } from '@/lib/sanity'
import { postQuery } from '@/lib/queries'
export const revalidate = 3600 // Revalidar cada hora como fallback
export async function generateStaticParams() {
// Solo pre-generar los 100 posts principales por tráfico
const topPosts = await sanityFetch({
query: `*[_type == "post"] | order(pageViews desc) [0...100] { "slug": slug.current }`
})
return topPosts.map((post) => ({ slug: post.slug }))
}
export default async function BlogPost({ params }) {
const post = await sanityFetch({
query: postQuery,
params: { slug: params.slug },
tags: [`post:${params.slug}`]
})
// ... renderizar post
}
Cuando los editores de contenido publican o actualizan en Sanity, un webhook golpea nuestro punto final de revalidación:
// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache'
import { NextRequest } from 'next/server'
export async function POST(req: NextRequest) {
const body = await req.json()
const secret = req.headers.get('x-sanity-webhook-secret')
if (secret !== process.env.SANITY_WEBHOOK_SECRET) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
// Revalidar contenido específico
if (body._type === 'post') {
revalidateTag(`post:${body.slug.current}`)
revalidateTag('posts-list')
}
return Response.json({ revalidated: true })
}
Las actualizaciones de contenido ahora aparecen en el sitio en vivo en menos de 3 segundos. Compara eso con la invalidación de caché de 4 minutos que tenían con WordPress + WP Rocket.
Autenticación para el portal de clientes
Las rutas del portal necesitaban autenticación del lado del servidor. Usamos middleware de Next.js combinado con su configuración Auth0 existente:
// middleware.ts
import { NextResponse } from 'next/server'
import { getSession } from '@auth0/nextjs-auth0/edge'
export async function middleware(req) {
if (req.nextUrl.pathname.startsWith('/portal')) {
const session = await getSession(req, NextResponse.next())
if (!session?.user) {
return NextResponse.redirect(new URL('/api/auth/login', req.url))
}
}
return NextResponse.next()
}
export const config = {
matcher: ['/portal/:path*']
}
Esto se ejecuta en el edge, por lo que las solicitudes no autenticadas se redirigen antes de que siquiera lleguen al servidor de aplicaciones. Rápido y seguro.
Mapa de redirección 301
Teníamos aproximadamente 340 URLs que cambiaron de estructura durante la migración. Un sitio de servicios financieros absolutamente no puede tener enlaces rotos — cada enlace entrante de presentaciones regulatorias, sitios de socios y contenido histórico necesita resolverse correctamente.
Construimos un mapa de redirección en next.config.js y lo complementamos con una búsqueda de redirección dinámica de Sanity para redirecciones gestionadas por editores:
// next.config.js (parcial)
module.exports = {
async redirects() {
return [
// Redirecciones estáticas para cambios de URL conocidos
...require('./redirects.json').map(r => ({
source: r.from,
destination: r.to,
permanent: true,
})),
]
},
}
Seis meses después del lanzamiento, Google Search Console muestra cero errores 404 de la migración. Cada redirección única está funcionando.
Lecciones aprendidas de la manera difícil
1. Los bloques Gutenberg de WordPress son un dolor de convertir
Subestimamos el esfuerzo para convertir bloques Gutenberg a Portable Text de Sanity. FinEdge había usado 23 tipos de bloque diferentes, incluyendo bloques personalizados que su agencia anterior construyó. Presupuesta al menos 20% más de tiempo del que crees para la transformación de contenido.
2. La capacitación del editor de contenido no es opcional
Studio de Sanity es intuitivo, pero no es WordPress. Realizamos tres sesiones de capacitación de 90 minutos y creamos un Studio de Sanity personalizado con flujos de trabajo guiados. El equipo de contenido pasó de escéptico a entusiasmado dentro de dos semanas, pero esa inversión de capacitación fue crítica.
3. El cumplimiento de servicios financieros agrega complejidad
Cada despliegue necesitaba un registro de auditoría. Cada cambio de contenido necesitaba ser registrado con marcas de tiempo e atribución de usuario. Construimos un complemento Sanity personalizado que registra todas las mutaciones de documentos en una tabla de solo adición en su base de datos PostgreSQL existente. Esta migración única tomó una semana extra que no estaba en el alcance original.
4. No olvides los formularios
Gravity Forms estaba manejando 14 tipos de formulario diferentes en el sitio de WordPress. Los reemplazamos con React Hook Form + validación Zod en el frontend y server actions en el backend, con envíos yendo a su CRM HubSpot existente. Esta migración sola tomó una semana completa.
Cronograma y estructura del equipo
Duración total del proyecto: 10 semanas
| Semana | Enfoque | Equipo |
|---|---|---|
| 1 | Arquitectura, diseño de esquema Sanity, auditoría de contenido | 2 devs, 1 arquitecto |
| 2-3 | Tubería de sincronización de contenido, personalización de Sanity Studio | 2 devs, 1 estratega de contenido |
| 4-5 | Construcción del sitio de marketing (Next.js) | 3 devs |
| 6-7 | Migración del portal, autenticación, formularios | 3 devs |
| 8 | Centro de documentación, auditoría SEO, mapa de redirecciones | 2 devs, 1 especialista en SEO |
| 9 | QA, regresión visual, pruebas de rendimiento | 2 devs, 1 QA |
| 10 | Cambio gradual de tráfico, monitoreo, desmantelamiento de WordPress | 2 devs, 1 DevOps |
El tamaño máximo del equipo fue de 4 personas. La mayoría del proyecto se ejecutó con 2-3 desarrolladores. Este no es un compromiso de 15 personas por 6 meses — es un equipo enfocado y experimentado ejecutando una migración bien planeada.
Si estás considerando una migración similar para tu organización, hemos documentado nuestro enfoque de desarrollo de CMS headless y nuestra estructura de precios es transparente. También estamos felices de saltar en una llamada para hablar sobre tu situación específica — comunícate aquí.
FAQ
¿Cuánto tiempo lleva típicamente una migración de WordPress a Next.js?
Para un sitio de esta complejidad (12,000 páginas, portal de clientes, centro de documentación), 10 semanas es realista con un equipo experimentado. Sitios de marketing más simples con 100-500 páginas pueden ser migrados en 4-6 semanas. La variable más grande es la complejidad del contenido — cuántos tipos de post personalizados, tipos de bloques y características dependientes de complementos estés ejecutando.
¿Puedes migrar WordPress a Next.js sin tiempo de inactividad?
Sí, pero requiere planeación. La clave es ejecutar ambos sistemas en paralelo con una tubería de sincronización de contenido, luego usar cambio de tráfico a nivel de DNS para mover gradualmente a los usuarios al nuevo sitio. Hemos hecho esto con éxito para múltiples clientes. El requisito crítico es que tu contenido permanezca sincronizado en ambos sistemas durante el período de transición.
¿Cuánto cuesta una migración de WordPress a CMS headless?
Depende mucho del alcance. Una migración de sitio de marketing directa podría costar $30K-$60K. Una migración empresarial como la de FinEdge — con un portal de clientes, requisitos de cumplimiento y 12,000 páginas — fue $185K. El cálculo del ROI importa más que el costo absoluto. La inversión de FinEdge se pagó en menos de 5 meses solo a través de ahorros de licencias.
¿Es Next.js realmente más rápido que WordPress?
En prácticamente todos los casos, sí — significativamente más rápido. WordPress genera HTML en cada solicitud (a menos que esté fuertemente cacheado), e incluso con complementos de caché como WP Rocket, estás limitado por el tiempo de respuesta de PHP y el peso del ecosistema de WordPress. Next.js con ISR o generación estática sirve páginas pre-construidas desde el edge. Típicamente vemos mejoras de 3-5x en Core Web Vitals.
¿Qué CMS headless debería usar con Next.js?
Depende de tu equipo y requisitos. Sanity sobresale en modelado de contenido personalizado y colaboración en tiempo real. Contentful es fuerte para equipos empresariales que desean un enfoque más estructurado y opinionado pero se vuelve caro por asiento. Storyblok es excelente si la edición visual es una prioridad. Para sitios más simples, incluso archivos Markdown en un repositorio de Git pueden funcionar. Evaluamos esto caso por caso — no hay una respuesta universal.
¿Pierdes SEO al migrar de WordPress a Next.js?
No si lo haces bien. Las tres cosas que importan: mapeo de redirección 301 completo para que ninguna URL existente regrese 404s, preservar todas las etiquetas meta y datos estructurados, y enviar sitemaps actualizados a Google Search Console inmediatamente después de la transición. FinEdge vio un aumento del 31% en tráfico orgánico dentro de 90 días, en gran parte impulsado por mejoras de Core Web Vitals.
¿Qué sucede con los complementos de WordPress después de la migración?
La funcionalidad de cada complemento necesita ser replicada o reemplazada. Algunos son directos — los complementos de SEO se reemplazan por metadatos en tus componentes Next.js, los complementos de caché se vuelven innecesarios, y los complementos de formularios se reemplazan con bibliotecas de formularios React. Otros, como complementos de registro de cumplimiento personalizados, necesitan código de reemplazo hecho a medida. Por eso una auditoría exhaustiva de complementos durante el descubrimiento es esencial.
¿Pueden los editores de contenido seguir usando un editor visual después de pasar a headless?
Sí. Sanity Studio proporciona una interfaz de edición personalizable con vista previa en tiempo real. Es diferente del editor de bloques de WordPress, pero la mayoría de los equipos de contenido lo prefieren después de la curva de aprendizaje inicial. La herramienta Presentation de Sanity ahora ofrece edición visual verdadera con funcionalidad de hacer clic para editar en la vista previa en vivo. También configuramos despliegues de vista previa en Vercel para que los editores puedan ver exactamente cómo se verá su contenido antes de publicar.