Headless WordPress + Next.js: cómo migrar y por qué hacerlo

Apoya mi contenido: 

Tabla de contenido

Apoya mi contenido: 

Headless WordPress + Next.js: cómo migrar y por qué hacerlo

Headless WordPress separa el CMS (panel de administración y contenido) del frontend. En este enfoque, WordPress actúa como fuente de datos y Next.js renderiza el sitio usando SSR/SSG/ISR. El resultado: más rendimiento, mejor DX (Developer Experience) y una arquitectura preparada para escalar.

¿Por qué migrar a Headless con Next.js?

  • Rendimiento superior: páginas estáticas (SSG) e Incremental Static Regeneration (ISR) para latencias muy bajas.
  • SEO sólido: HTML prerenderizado, control total de metadatos y rutas limpias.
  • Experiencias ricas: React + ecosistema moderno (TypeScript, SWR/React Query, Tailwind, etc.).
  • Escalabilidad y seguridad: el panel WP queda aislado; el público consume solo el frontend desplegado en CDN.
  • Multicanal: sirve el mismo contenido a web, apps móviles o dispositivos IoT desde WordPress.

Antes de empezar

  • Actualiza WordPress, PHP (8.1+), base de datos y revisa compatibilidad de plugins.
  • Define modelo de contenido (Entradas, Páginas, CPT, taxonomías, campos ACF, etc.).
  • Elige API: WPGraphQL (recomendado) o REST API nativa.

Stack recomendado

  • WordPress (Headless) con plugins: WPGraphQL, WPGraphQL for ACF (si usas ACF), JWT o OAuth (si requieres auth).
  • Next.js 14/15 con App Router, TypeScript, next/image, next-seo o metadatos del App Router.
  • Vercel (o similar) para despliegue con ISR y CDN global.

Pasos para la migración

1) Preparar WordPress como API

  1. Instala y configura WPGraphQL (o expón rutas de REST API).
  2. Modela el contenido: CPT, taxonomías y campos (ACF). Verifica que el esquema GraphQL exponga todo lo necesario.
  3. Crea webhooks (por ejemplo con WP Webhooks) que notifiquen a Next.js para revalidar páginas al publicar/actualizar.
  4. Activa CORS para permitir peticiones desde tu dominio del frontend.

2) Crear el proyecto Next.js

npx create-next-app@latest headless-wp --ts
cd headless-wp
npm i @apollo/client graphql    # (si usas GraphQL)
# o bien npm i swr axios        # (si prefieres REST + SWR)

Ejemplo con GraphQL (App Router)

lib/apollo-client.ts

import { ApolloClient, InMemoryCache } from "@apollo/client";

export const client = new ApolloClient({
  uri: process.env.NEXT_PUBLIC_WP_GRAPHQL_ENDPOINT,
  cache: new InMemoryCache(),
});

app/page.tsx (home estática con revalidación)

import { gql } from "@apollo/client";
import { client } from "@/lib/apollo-client";

export const revalidate = 60; // ISR: revalida cada 60s

export default async function Home() {
  const { data } = await client.query({
    query: gql`{
      posts(first: 6) { nodes { id title uri excerpt } }
    }`,
    fetchPolicy: "no-cache"
  });

  return (
    <main>
      <h1>Blog</h1>
      <ul>
        {data.posts.nodes.map((p: any) => (
          <li key={p.id}><a href={p.uri}>{p.title}</a></li>
        ))}
      </ul>
    </main>
  );
}

Rutas dinámicas de posts

app/[…slug]/page.tsx

import { gql } from "@apollo/client";
import { client } from "@/lib/apollo-client";

export const revalidate = 300;

export async function generateStaticParams() {
  const { data } = await client.query({
    query: gql`{ posts(first: 100) { nodes { slug } } }`,
    fetchPolicy: "no-cache"
  });
  return data.posts.nodes.map((n: any) => ({ slug: [n.slug] }));
}

export default async function Post({ params }: { params: { slug: string[] } }) {
  const slug = params.slug.at(-1);
  const { data } = await client.query({
    query: gql`query ($slug: ID!) {
      post(id: $slug, idType: SLUG) { title content date featuredImage { node { sourceUrl width height } } }
    }`,
    variables: { slug },
    fetchPolicy: "no-cache"
  });

  const post = data.post;
  return (
    <article>
      <h1>{post.title}</h1>
      {post.featuredImage?.node && (
        <img src={post.featuredImage.node.sourceUrl} width={post.featuredImage.node.width} height={post.featuredImage.node.height} alt={post.title} />
      )}
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

3) Imágenes y CDN

  • Usa next/image con el dominio del WP configurado en next.config.js para optimización automática.
  • Considera mover la librería multimedia a un bucket S3/Cloud Storage con plugin (Offload Media) para menos carga al WP.

4) SEO, metadatos y sitemap

  • En App Router, define generateMetadata o instala next-seo.
  • Genera /sitemap.xml y /robots.txt con next-sitemap.

5) Vista previa de borradores (Preview Mode)

  1. Crea una ruta API en Next.js (/api/preview) que valide un token y habilite el modo preview.
  2. En WordPress, configura la URL de vista previa para apuntar a esa ruta con el postId.

6) Revalidación por webhook

En /app/api/revalidate/route.ts:

import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
  const secret = req.nextUrl.searchParams.get("secret");
  if (secret !== process.env.REVALIDATE_SECRET) return NextResponse.json({ ok: false }, { status: 401 });

  const path = (await req.json()).path || "/";
  try {
    // @ts-ignore: disponible en runtime de Vercel
    await res.revalidate(path);
    return NextResponse.json({ revalidated: true, path });
  } catch (e) {
    return NextResponse.json({ revalidated: false, message: String(e) }, { status: 500 });
  }
}

Desde WordPress, envía el webhook al publicar y pasa la ruta afectada.

Consideraciones y buenas prácticas

  • Autenticación: para áreas privadas, usa JWT/OAuth y middleware de Next.
  • Cache: SWR/React Query en cliente y caché de fetch en servidor; evita sobrecargar al WP.
  • Accesibilidad y i18n con next-intl o next-i18next.
  • Monitorización: registra métricas Web Vitals y errores (Sentry/LogRocket).

Desventajas (lo que debes saber)

  • Mayor complejidad inicial que un tema clásico de WordPress.
  • Algunas funciones de plugins visuales no aplican directamente al frontend (requieren integración vía API).
  • Coste operativo: CMS + hosting del frontend + posibles servicios de medios/edge.

Checklist de migración

  • ✓ Inventario de contenido y URL actuales (para redirecciones 301).
  • ✓ API lista (WPGraphQL/REST) y esquema validado.
  • ✓ Next.js con SSG/ISR y rutas equivalentes.
  • ✓ SEO: metadatos, sitemap, robots.txt, canonicals y redirects.
  • ✓ Webhooks de revalidación y vista previa de borradores.
  • ✓ Pruebas de rendimiento, accesibilidad y core web vitals.

Conclusión

Migrar a Headless WordPress + Next.js ofrece un salto notable en rendimiento, seguridad y flexibilidad. Si tu proyecto necesita velocidad, SEO robusto y una UX moderna, el enfoque headless es una apuesta ganadora.

👉 ¿Quieres que planifiquemos y ejecutemos tu migración headless de principio a fin?
Contáctanos aquí.

Artículos relacionados

¡Comunícate con nosotros!