He migrado más de una docena de sitios WordPress a Next.js en los últimos tres años. Algunos funcionaron sin problemas. Otros me hicieron cuestionarme mis decisiones profesionales a las 2 AM de un martes. La diferencia entre estos dos resultados casi siempre se debió a la planificación — específicamente, entender qué estaba realmente haciendo WordPress en el sitio antes de arrancarlo.

Esta guía es todo lo que desearía que alguien me hubiera entregado antes de mi primera migración. Cubriremos el viaje completo: evaluar si deberías migrar, elegir tu CMS headless, mover contenido, reconstruir plantillas, manejar SEO sin perder rankings y desplegar en Vercel con una configuración que no colapse bajo picos de tráfico.

Vamos a ello.

Migración de WordPress a Next.js en Vercel: Guía 2026

Tabla de Contenidos

¿Por Qué Migrar de WordPress a Next.js en 2026?

Seamos honestos — WordPress aún impulsa aproximadamente el 40% de la web en 2026. No va a desaparecer. Pero las razones para irse se han vuelto más convincentes:

Techo de rendimiento. Incluso con plugins de caché agresivos (WP Rocket, W3 Total Cache), la mayoría de sitios WordPress chocan con una pared alrededor de 70-80 en puntuaciones de rendimiento de Lighthouse. El exceso de plugins, PHP que bloquea el renderizado y consultas de base de datos en cada carga de página crean una sobrecarga que ningún nivel de optimización puede eliminar completamente.

Área de superficie de seguridad. WordPress tuvo 149 vulnerabilidades documentadas en 2025 en el núcleo y plugins populares. Cada plugin es un vector de ataque. Cada actualización de tema es un potencial problema. Si ejecutas WooCommerce, el área de superficie se duplica.

Experiencia del desarrollador. Si tu equipo conoce React, programar en plantillas PHP se siente como escribir con tu mano no dominante. El App Router de Next.js 15, Server Components y caché integrado te dan un flujo de trabajo de desarrollo moderno que WordPress no puede igualar.

Costo a escala. El alojamiento WordPress gestionado (WP Engine, Kinsta) cuesta $30-$300/mes para un rendimiento decente. El plan Pro de Vercel a $20/usuario/mes con funciones edge y escalado automático a menudo cuesta menos mientras funciona mejor.

Dicho esto — no migres solo porque es tendencia. Si tu sitio es un blog simple con 50 posts y tu cliente lo actualiza semanalmente a través del admin de WordPress, una migración podría crear más problemas de los que resuelve. Los mejores candidatos para migración son:

  • Sitios con 500+ páginas que necesitan mejor rendimiento
  • Equipos que desean desarrollo basado en componentes
  • Sitios donde conflictos de plugins causan pesadillas de mantenimiento
  • Sitios de e-commerce que alcanzan límites de rendimiento de WooCommerce
  • Sitios de marketing que necesitan pruebas A/B y personalización en el edge

Auditoría Previa a la Migración: Qué WordPress Está Realmente Haciendo

Aquí es donde fallan la mayoría de migraciones. La gente cree que está migrando un blog, pero WordPress está realmente manejando formularios de contacto, redireccionamientos, optimización de imágenes, búsqueda, comentarios, autenticación, trabajos cron y quince otras cosas enterradas en configuraciones de plugin.

Antes de escribir una sola línea de código Next.js, documenta todo:

Inventario de Plugins

Exporta tu lista de plugins y categoriza cada uno:

wp plugin list --status=active --format=csv > active-plugins.csv

Para cada plugin, responde: ¿Qué hace esto y qué lo reemplaza en el ecosistema Next.js?

Plugin de WordPress Función Reemplazo Next.js
Yoast SEO Etiquetas meta, mapas de sitio, schema next-seo + ruta sitemap.xml personalizada
WP Rocket Caché, minificación Vercel Edge Cache + Next.js integrado
Contact Form 7 Manejo de formularios React Hook Form + ruta API o Formspree
Wordfence Seguridad No necesario (sin superficie de admin)
WPML Multilingüe next-intl o enrutamiento i18n integrado
WooCommerce E-commerce Shopify Storefront API o Saleor
Advanced Custom Fields Modelos de contenido personalizados Modelado de contenido de tu CMS headless
Redirection Redireccionamientos de URL Redireccionamientos en next.config.js o configuración de Vercel
WP Cron Tareas programadas Vercel Cron Jobs o servicio separado
Imagify Optimización de imágenes next/image con Optimización de Imágenes de Vercel

Inventario de Contenido

Cuenta y categoriza tu contenido:

SELECT post_type, post_status, COUNT(*) 
FROM wp_posts 
GROUP BY post_type, post_status;

No olvides: tipos de post personalizados, términos de taxonomía, perfiles de usuario, estructuras de menú, configuraciones de widgets y valores de opción. Ese sitio WordPress "simple" probablemente tiene más tipos de contenido de los que crees.

Mapeo de URL

Exporta cada URL. Cada una. Usa Screaming Frog o un rastreo de sitemap simple:

curl -s https://yoursite.com/sitemap_index.xml | \
grep -oP '<loc>\K[^<]+' | \
xargs -I {} curl -s {} | \
grep -oP '<loc>\K[^<]+' > all-urls.txt

Este archivo es oro. Lo usarás para mapeo de redireccionamientos, preservación de SEO y pruebas de control de calidad después de la migración.

Migración de WordPress a Next.js en Vercel: Guía 2026 - arquitectura

Elegir tu Backend CMS Headless

Necesitas un lugar para almacenar y administrar contenido. Los tres caminos más comunes en 2026:

Opción 1: WordPress como CMS Headless

Sí, puedes mantener WordPress como backend y usar Next.js como frontend. WPGraphQL (ahora en v2.1) hace esto sorprendentemente viable. Tus editores conservan la interfaz de admin familiar. Obtienes un frontend moderno.

// lib/wordpress.js
const API_URL = process.env.WORDPRESS_GRAPHQL_URL;

export async function getPostBySlug(slug) {
  const res = await fetch(API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: `
        query PostBySlug($slug: ID!) {
          post(id: $slug, idType: SLUG) {
            title
            content
            date
            featuredImage {
              node {
                sourceUrl
                altText
              }
            }
            seo {
              title
              metaDesc
              opengraphImage {
                sourceUrl
              }
            }
          }
        }
      `,
      variables: { slug },
    }),
    next: { revalidate: 60 },
  });
  const json = await res.json();
  return json.data.post;
}

¿La desventaja? Aún mantienes una instalación de WordPress. Actualizaciones de seguridad, gestión de versiones de PHP, copias de seguridad de base de datos — todo sigue en tu plato. Y aún estás pagando por alojamiento de WordPress.

Opción 2: CMS Headless de Propósito Específico

Esto es lo que recomiendo para la mayoría de migraciones. Mueve tu contenido a un CMS que fue creado desde el principio para entrega API-first.

CMS Precio (2026) Mejor Para Modelado de Contenido Tipo de API
Sanity Nivel gratuito, $15/usuario/mes Pro Contenido complejo, colaboración en tiempo real Excelente, definido por código GROQ + GraphQL
Contentful Nivel gratuito, $300/mes Team Empresa, equipos grandes Bueno, definido por UI REST + GraphQL
Storyblok Nivel gratuito, €106/mes Business Edición visual, componentes Excelente, edición visual REST + GraphQL
Strapi v5 Gratuito (auto-alojado), Cloud desde $29/mes Control total, código abierto Flexible, definido por UI REST + GraphQL
Payload CMS 3.0 Gratuito (auto-alojado) Desarrolladores que quieren code-first Excelente, definido por código REST + GraphQL

Si tu equipo en Social Animal está manejando la migración, típicamente recomendamos Sanity o Payload para desarrollo de CMS headless — dan a los desarrolladores el máximo control sobre modelado de contenido mientras mantienen contentos a los editores.

Opción 3: Markdown/MDX en el Repositorio

Para blogs de desarrolladores y sitios de documentación, almacenar contenido como archivos MDX en tu repositorio de Git es el enfoque más simple. Sin CMS para administrar, sin llamadas a API, contenido versionado junto a código. Pero esto solo funciona si tus editores de contenido se sienten cómodos con flujos de trabajo de Git.

Estrategia de Migración de Contenido

Exportando desde WordPress

La exportación integrada de WordPress (Herramientas → Exportar) te da un archivo XML. Es un comienzo, pero está desordenado. Para migración estructurada, uso un script personalizado de WP-CLI:

// export-content.php
<?php
$posts = get_posts([
    'post_type' => ['post', 'page', 'your_custom_type'],
    'posts_per_page' => -1,
    'post_status' => 'publish',
]);

$export = [];
foreach ($posts as $post) {
    $export[] = [
        'id' => $post->ID,
        'title' => $post->post_title,
        'slug' => $post->post_name,
        'content' => apply_filters('the_content', $post->post_content),
        'excerpt' => $post->post_excerpt,
        'date' => $post->post_date,
        'modified' => $post->post_modified,
        'author' => get_the_author_meta('display_name', $post->post_author),
        'categories' => wp_get_post_categories($post->ID, ['fields' => 'names']),
        'tags' => wp_get_post_tags($post->ID, ['fields' => 'names']),
        'featured_image' => get_the_post_thumbnail_url($post->ID, 'full'),
        'acf' => function_exists('get_fields') ? get_fields($post->ID) : [],
        'yoast' => [
            'title' => get_post_meta($post->ID, '_yoast_wpseo_title', true),
            'description' => get_post_meta($post->ID, '_yoast_wpseo_metadesc', true),
        ],
    ];
}

file_put_contents('export.json', json_encode($export, JSON_PRETTY_PRINT));

Transformando Contenido

El contenido de WordPress se almacena como HTML con marcado de bloque Gutenberg. Tendrás que decidir: ¿mantener el HTML y renderizarlo, o convertir al formato estructurado de tu CMS?

Para Sanity, uso @sanity/block-tools para convertir HTML a Portable Text. Para Contentful, su CLI de migración maneja la conversión de rich text. De cualquier forma, presupuesta tiempo para limpieza de contenido — el contenido de WordPress está lleno de [shortcodes], estilos inline y HTML roto que necesita limpieza.

// migrate-to-sanity.js
import { htmlToBlocks } from '@sanity/block-tools';
import { JSDOM } from 'jsdom';
import { Schema } from '@sanity/schema';

const schema = Schema.compile({ /* your schema */ });
const blockContentType = schema.get('post')
  .fields.find(f => f.name === 'body').type;

function convertPost(wpPost) {
  return {
    _type: 'post',
    title: wpPost.title,
    slug: { current: wpPost.slug },
    publishedAt: wpPost.date,
    body: htmlToBlocks(
      wpPost.content,
      blockContentType,
      { parseHtml: (html) => new JSDOM(html).window.document }
    ),
  };
}

Migración de Imágenes

No saltes esto. Descarga cada imagen de wp-content/uploads, recarga a tu CMS o CDN (Cloudinary, Vercel Blob Storage, S3) y actualiza todas las referencias de contenido. Típicamente escribo un script que:

  1. Rastrea el JSON de exportación para URLs de imágenes
  2. Descarga cada imagen
  3. Sube a el nuevo almacenamiento
  4. Crea un archivo de mapeo de URL
  5. Ejecuta buscar-y-reemplazar en todo el contenido

Reconstruir tu Frontend en Next.js 15

Next.js 15 (estable desde finales de 2024, con 15.2 actual en 2026) usa el App Router por defecto. Aquí está la estructura que uso para sitios con mucho contenido:

app/
├── layout.tsx          # Layout raíz con fuentes, analítica
├── page.tsx            # Página de inicio
├── blog/
│   ├── page.tsx        # Listado de blog con paginación
│   └── [slug]/
│       └── page.tsx    # Posts de blog individuales
├── [slug]/
│   └── page.tsx        # Páginas genéricas
├── sitemap.ts          # Generación de sitemap dinámico
├── robots.ts           # robots.txt
└── not-found.tsx       # 404 personalizado

Generación Estática con ISR

Para la mayoría de páginas de contenido, Incremental Static Regeneration es el punto dulce — rendimiento estático con frescura dinámica:

// app/blog/[slug]/page.tsx
import { getPostBySlug, getAllPostSlugs } from '@/lib/cms';
import { notFound } from 'next/navigation';

export async function generateStaticParams() {
  const slugs = await getAllPostSlugs();
  return slugs.map((slug) => ({ slug }));
}

export async function generateMetadata({ params }) {
  const post = await getPostBySlug(params.slug);
  if (!post) return {};
  return {
    title: post.seo?.title || post.title,
    description: post.seo?.description || post.excerpt,
    openGraph: {
      images: [post.featuredImage?.url],
    },
  };
}

export const revalidate = 3600; // Revalidar cada hora

export default async function BlogPost({ params }) {
  const post = await getPostBySlug(params.slug);
  if (!post) notFound();

  return (
    <article className="prose lg:prose-xl">
      <h1>{post.title}</h1>
      <time dateTime={post.date}>{formatDate(post.date)}</time>
      <PostBody content={post.body} />
    </article>
  );
}

Para sitios que necesitan actualizaciones en tiempo real (noticias, contenido en vivo), usa revalidación bajo demanda a través de webhooks de tu CMS. La mayoría de plataformas de CMS headless soportan disparadores de webhooks al publicar contenido.

Si estás mirando desarrollo de Next.js y quieres entender los trade-offs de renderizado más profundamente, hemos escrito sobre eso por separado.

Estructura de URL y Preservación de SEO

Esto es innegociable. Si pierdes tu estructura de URL, pierdes tus rankings de búsqueda. Punto.

Mapa de Redireccionamiento

WordPress usa patrones de URL como /2024/03/post-slug/ o /category/term/. Tu sitio Next.js probablemente usa /blog/post-slug. Crea un mapa de redireccionamiento:

// next.config.js
module.exports = {
  async redirects() {
    return [
      // URLs basadas en fecha a slugs limpios
      {
        source: '/:year(\\d{4})/:month(\\d{2})/:slug',
        destination: '/blog/:slug',
        permanent: true,
      },
      // Archivos de categoría
      {
        source: '/category/:slug',
        destination: '/blog?category=:slug',
        permanent: true,
      },
      // Paginación
      {
        source: '/page/:num',
        destination: '/blog?page=:num',
        permanent: true,
      },
      // URLs de feed
      {
        source: '/feed',
        destination: '/rss.xml',
        permanent: true,
      },
    ];
  },
};

Para sitios grandes (1000+ redireccionamientos), usa la configuración vercel.json o middleware en lugar de redireccionamientos en next.config.js — los redireccionamientos de next.config.js tienen un límite suave de alrededor de 1024 entradas antes de que los tiempos de construcción comiencen a sufrir.

Datos Estructurados

Plugins de WordPress como Yoast generan automáticamente JSON-LD. Necesitas replicar esto:

// components/structured-data.tsx
export function ArticleSchema({ post }) {
  const schema = {
    '@context': 'https://schema.org',
    '@type': 'Article',
    headline: post.title,
    datePublished: post.date,
    dateModified: post.modified,
    author: {
      '@type': 'Person',
      name: post.author,
    },
    image: post.featuredImage?.url,
    publisher: {
      '@type': 'Organization',
      name: 'Your Site Name',
      logo: { '@type': 'ImageObject', url: '/logo.png' },
    },
  };

  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
    />
  );
}

Mapa de Sitio XML

Next.js 15 hace que los mapas de sitio dinámicos sean sencillos:

// app/sitemap.ts
import { getAllPosts, getAllPages } from '@/lib/cms';

export default async function sitemap() {
  const posts = await getAllPosts();
  const pages = await getAllPages();

  return [
    { url: 'https://yoursite.com', lastModified: new Date() },
    ...pages.map((page) => ({
      url: `https://yoursite.com/${page.slug}`,
      lastModified: page.modified,
    })),
    ...posts.map((post) => ({
      url: `https://yoursite.com/blog/${post.slug}`,
      lastModified: post.modified,
    })),
  ];
}

Despliegue en Vercel: Configuración que Realmente Funciona

Configuración del Proyecto

npx create-next-app@latest my-migrated-site --typescript --tailwind --app
cd my-migrated-site
vercel link

Variables de Entorno

Establece estas en el dashboard de Vercel, no en archivos .env comprometidos a Git:

CMS_API_URL=https://your-cms-api-endpoint
CMS_API_TOKEN=your-read-only-token
REVALIDATION_SECRET=a-random-string-for-webhook-auth
SITE_URL=https://yoursite.com

Configuración de Vercel

// vercel.json
{
  "crons": [
    {
      "path": "/api/revalidate-sitemap",
      "schedule": "0 */6 * * *"
    }
  ],
  "headers": [
    {
      "source": "/fonts/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
      ]
    }
  ]
}

Webhook de Revalidación Bajo Demanda

// app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidation-secret');
  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
  }

  const body = await request.json();
  const { slug, type } = body;

  if (type === 'post') {
    revalidatePath(`/blog/${slug}`);
    revalidatePath('/blog'); // Revalidar listado también
  } else {
    revalidatePath(`/${slug}`);
  }

  return NextResponse.json({ revalidated: true });
}

Apunta tu webhook de CMS a https://yoursite.com/api/revalidate con el header secreto. Ahora las actualizaciones de contenido aparecen dentro de segundos sin reconstrucciones completas.

Benchmarks de Rendimiento: Antes y Después

Estos son números reales de migraciones completadas por Social Animal en 2025-2026:

Métrica WordPress (WP Engine) Next.js (Vercel) Mejora
Rendimiento de Lighthouse 62-78 95-100 +30-40%
Largest Contentful Paint 2.8-4.2s 0.8-1.4s 60-70% más rápido
Time to First Byte 800ms-1.5s 50-120ms 90%+ más rápido
Cumulative Layout Shift 0.12-0.25 0.01-0.05 ~80% reducción
Costo de alojamiento mensual $115/mes promedio $20-40/mes 60-80% ahorros
Tiempo de construcción (500 páginas) N/A (dinámico) 45-90 segundos N/A
Páginas/segundo (ISR) 15-30 req/s 10,000+ desde edge Órdenes de magnitud

La mejora de TTFB por sí sola vale la migración. WordPress genera cada página a través de PHP y MySQL. Vercel sirve páginas pre-renderizadas desde nodos edge en 300+ ubicaciones en todo el mundo.

Trampas Comunes de Migración

Trampa 1: Olvidar feeds RSS de WordPress. Si la gente se suscribe a tu feed, redirige /feed/ y /rss/ a un nuevo endpoint de RSS. Next.js no genera feeds por defecto — necesitas una ruta personalizada.

Trampa 2: Perder shortcodes de WordPress. El contenido exportado de WordPress está lleno de [gallery], [embed] y shortcodes específicos de plugins. Si no parses y conviertes estos, se renderizan como texto plano. Escribe transformadores para cada tipo de shortcode que tu contenido usa.

Trampa 3: Ignorar datos de comentarios de WordPress. Si tienes valiosos hilos de comentarios, migralos a un servicio como Disqus o construye un sistema de comentarios personalizado. La mayoría de gente simplemente deja caer comentarios, pero verifica con stakeholders primero.

Trampa 4: No probar enlaces internos. El contenido de WordPress está lleno de enlaces internos usando URLs absolutas (https://yoursite.com/old-path/). Estos necesitan actualizarse a rutas relativas o tu nueva estructura de URL. Un simple buscar-y-reemplazar con regex durante migración maneja la mayoría de casos.

Trampa 5: Olvidar referencias de wp-content/uploads. Incluso después de migrar imágenes, contenido antiguo puede hacer referencia a rutas /wp-content/uploads/2024/03/image.jpg. Configura un redireccionamiento catch-all o proxy estos a tu nuevo CDN de imágenes.

Si esto se siente abrumador, es honestamente normal. Una migración adecuada toma 4-12 semanas dependiendo de la complejidad del sitio. Revisa nuestro pricing o contáctanos directamente si quieres manos experimentadas en el proyecto.

Preguntas Frecuentes

¿Cuánto tiempo toma una migración de WordPress a Next.js? Para un sitio con 100-500 páginas, espera 4-8 semanas con un desarrollador dedicado. Sitios más grandes con tipos de post personalizados, e-commerce o contenido multilingüe pueden tomar 8-16 semanas. La migración de contenido en sí es generalmente el 20% del trabajo — el otro 80% es reconstruir plantillas, manejar casos extremos y pruebas de control de calidad de cada URL.

¿Perderé mis rankings de Google durante la migración? No si manejas redireccionamientos correctamente. Implementa redireccionamientos 301 para cada URL que cambie, preserva tus títulos meta y descripciones, envía tu nuevo sitemap a Google Search Console y usa la herramienta Change of Address si tu dominio cambia. Espera una pequeña fluctuación de ranking durante 2-4 semanas, luego recuperación o mejora mientras Google reconoce mejores Core Web Vitals.

¿Puedo mantener WordPress como mi CMS con Next.js? Absolutamente. Esto se llama "WordPress headless" y es un enfoque popular. Usa WPGraphQL para exponer tu contenido como una API, luego consúmela desde Next.js. Tus editores mantienen el admin de WordPress que conocen. La desventaja principal es que aún mantienes una instalación de WordPress — actualizaciones de seguridad, alojamiento, toda la pila.

¿Cuánto cuesta migrar de WordPress a Next.js? DIY con un desarrollador: 100-300 horas de trabajo. Migración de agencia: típicamente $15,000-$75,000 dependiendo de complejidad. Los costos de alojamiento continuo generalmente disminuyen — Vercel Pro a $20/usuario/mes versus alojamiento WordPress gestionado a $50-$300/mes. El ROI viene de costos de alojamiento reducidos, mejor rendimiento (que mejora tasas de conversión) y menor sobrecarga de mantenimiento.

¿Debería usar el Pages Router o App Router en Next.js 15? App Router, completamente. En 2026, el App Router es el default estable con Server Components, streaming y rutas paralelas. El Pages Router aún funciona y no está deprecado, pero nuevas características y optimizaciones son App Router-first. Cada migración que hacemos en Social Animal usa el App Router exclusivamente. Revisa nuestras capacidades de desarrollo Next.js para más en nuestro enfoque.

¿Qué hay de formularios y funcionalidad dinámica? Las rutas de API de Next.js (o Server Actions en el App Router) manejan envíos de formularios, búsqueda, autenticación y cualquier lógica del lado del servidor. Para formularios de contacto, puedes usar Server Actions con un servicio como Resend para entrega de email. Para búsqueda, considera Algolia o Meilisearch. Para autenticación, NextAuth.js (ahora Auth.js v5) cubre la mayoría de casos de uso.

¿Es Vercel la única opción para alojamiento de Next.js? No. Puedes desplegar Next.js en Netlify, AWS Amplify, Cloudflare Pages o auto-alojarlo con Node.js. Sin embargo, Vercel es creado por el equipo de Next.js y la integración se ve — ISR, middleware edge, optimización de imágenes y analítica todo funciona mejor en Vercel. La brecha de DX entre Vercel y alternativas se ha estrechado en 2026, pero Vercel sigue siendo el camino de menor resistencia.

¿Qué si necesito migrar una tienda WooCommerce? Este es un proyecto más grande. La mayoría de equipos migran el escaparate a Next.js mientras mueven el backend de comercio a Shopify (usando Storefront API), Medusa.js o Saleor. El framework Hydrogen de Shopify es otra opción, pero si quieres control total sobre el frontend, Next.js con la API de Shopify es el camino más probado. Espera que la migración de e-commerce agregue 4-8 semanas a tu cronograma.