Headless WordPress con Next.js 15 y GraphQL: Rendimiento Extremo
[INFO] Este artículo está diseñado para desarrolladores con experiencia intermedia en WordPress y React. Se asume familiaridad con la terminal y la gestión de paquetes npm.
La arquitectura web tradicional, donde el frontend y el backend viven en el mismo servidor, se está quedando obsoleta para proyectos que exigen rendimiento frontend extremo. La solución moderna es el headless WordPress, que separa el CMS de la capa de presentación. Al combinar WordPress como backend de contenidos con Next.js 15 y GraphQL, obtenemos una máquina de velocidad imparable, capaz de servir páginas casi instantáneas y escalar sin sudor.
En este artículo, exploraremos cómo configurar un ecosistema headless de alto rendimiento, aprovechando las últimas características de Next.js 15, como el App Router, Server Components y el renovado soporte para ISR (Incremental Static Regeneration). Olvídate del pesado loop de WordPress. Prepárate para un rendimiento frontend que hará sonrojar a cualquier sitio tradicional.
¿Por qué Headless WordPress con Next.js 15?
La combinación no es casualidad. WordPress sigue siendo el CMS más flexible del mundo para gestión de contenidos, pero su stack frontend (PHP + temas) es un cuello de botella. Al extraer la capa de presentación:
- Rendimiento frontend puro: Next.js genera HTML estático (SSG) o lo renderiza en el servidor (SSR) con una eficiencia que PHP jamás alcanzará.
- Escalabilidad separada: Puedes escalar el frontend (Vercel, Netlify) independientemente del backend (tu hosting de WordPress).
- Experiencia de desarrollo moderna: React Server Components, TypeScript, Tailwind CSS y un ecosistema de herramientas frontend de primer nivel.
- GraphQL como pegamento: En lugar de la pesada REST API de WordPress, GraphQL te permite pedir exactamente los datos que necesitas, ni uno más. Menos payload, más velocidad.
Next.js 15, con su App Router estable y mejoras en ISR, lleva esto al siguiente nivel. Ya no necesitas un plugin de caché externo. El propio framework gestiona la regeneración de páginas cuando el contenido cambia.
Configuración del Backend: WordPress como Headless CMS
Primero, necesitas un WordPress limpio (recomendamos una instalación nueva). Los pasos son mínimos:
- Instala y activa el plugin WPGraphQL. Este plugin expone tu contenido de WordPress como un endpoint GraphQL (normalmente en
/graphql). - (Opcional pero recomendado) Instala Advanced Custom Fields (ACF) y su extensión WPGraphQL for ACF. Esto te permitirá añadir campos personalizados y exponerlos directamente en GraphQL.
- Configura los Permalinks en Ajustes > Enlaces permanentes a cualquier opción que no sea "Simple". Recomendamos "Nombre de la entrada".
[TIP] No necesitas instalar ningún plugin de caché en WordPress. La caché la gestionará Next.js desde el frontend. Mantén el backend limpio y rápido.
Una vez activo, tu endpoint GraphQL estará listo. Puedes probarlo con herramientas como GraphiQL o directamente desde tu navegador.
Preparando el Frontend: Next.js 15 y Apollo Client
Ahora vamos a crear el proyecto Next.js. Abre tu terminal y ejecuta:
npx create-next-app@latest mi-headless-blog --typescript --tailwind --eslint
cd mi-headless-blog
Instala las dependencias necesarias para GraphQL:
npm install @apollo/client graphql
Crea un cliente Apollo para conectarte a tu WordPress. Dentro de lib/apollo-client.ts:
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: process.env.NEXT_PUBLIC_WORDPRESS_URL + '/graphql',
cache: new InMemoryCache(),
});
export default client;
Crea un archivo .env.local en la raíz del proyecto:
NEXT_PUBLIC_WORDPRESS_URL=https://tusitio.com
Estrategias de Renderizado: SSR, SSG e ISR en Next.js 15
Aquí está el corazón del rendimiento frontend. Next.js 15 te ofrece tres modos principales, y elegir el correcto es clave.
Server-Side Rendering (SSR) con GraphQL
Úsalo para páginas que necesitan datos siempre frescos (por ejemplo, un dashboard de usuario). Cada petición genera HTML en el servidor.
// app/perfil/page.tsx
import { client } from '@/lib/apollo-client';
import { gql } from '@apollo/client';
const GET_USER = gql`
query GetUser($slug: ID!) {
user(id: $slug) {
name
posts {
nodes {
title
}
}
}
}
`;
export default async function PerfilPage({ params }: { params: { slug: string } }) {
const { data } = await client.query({
query: GET_USER,
variables: { slug: params.slug },
fetchPolicy: 'no-cache', // Fuerza SSR
});
return <div>{data.user.name}</div>;
}
Static Site Generation (SSG) para Páginas Estáticas
Para páginas que raramente cambian (como "Acerca de" o "Contacto"), genera el HTML en build time. Es la opción más rápida.
// app/acerca/page.tsx
import { client } from '@/lib/apollo-client';
import { gql } from '@apollo/client';
const GET_PAGE = gql`
query GetPage {
page(id: "about", idType: URI) {
title
content
}
}
`;
export default async function AcercaPage() {
const { data } = await client.query({
query: GET_PAGE,
});
return (
<article>
<h1>{data.page.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.page.content }} />
</article>
);
}
Incremental Static Regeneration (ISR) – El Santo Grial
Esta es la joya de Next.js 15. Combina la velocidad del SSG con la frescura del SSR. Puedes definir un tiempo de revalidación (en segundos) y, además, forzar la regeneración bajo demanda usando revalidatePath().
// app/blog/[slug]/page.tsx
import { client } from '@/lib/apollo-client';
import { gql } from '@apollo/client';
import { notFound } from 'next/navigation';
const GET_POST = gql`
query GetPost($slug: ID!) {
post(id: $slug, idType: SLUG) {
title
content
date
}
}
`;
export default async function BlogPost({ params }: { params: { slug: string } }) {
const { data } = await client.query({
query: GET_POST,
variables: { slug: params.slug },
context: {
fetchOptions: {
next: { revalidate: 60 }, // ISR: regenera cada 60 segundos si hay tráfico
},
},
});
if (!data?.post) {
notFound();
}
return (
<article>
<h1>{data.post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.post.content }} />
</article>
);
}
[WARNING] El ISR con revalidate funciona, pero ten cuidado con el stale-while-revalidate. Si regeneras cada 60 segundos, un usuario puede ver una versión de hasta 60 segundos de antigüedad. Para contenido que necesita inmediatez, usa SSR.
Para una regeneración instantánea cuando publiques en WordPress, puedes usar On-Demand ISR. Necesitas configurar un webhook en WordPress que llame a una API route de Next.js.
// 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-revalidate-secret');
if (secret !== process.env.REVALIDATION_SECRET) {
return NextResponse.json({ message: 'Invalid secret' }, { status: 401 });
}
revalidatePath('/blog/[slug]', 'page');
return NextResponse.json({ revalidated: true });
}
Luego, desde WordPress (con un plugin como WP Webhooks), envías una petición POST a /api/revalidate con el header secreto. ¡Magia!
Optimización de Imágenes y Assets
El rendimiento frontend no es solo HTML. Las imágenes son el mayor lastre. Next.js 15 ofrece un componente <Image> que optimiza automáticamente.
Para imágenes de WordPress, asegúrate de que el endpoint GraphQL devuelva las URLs de las imágenes en diferentes tamaños. Luego, en tu componente:
import Image from 'next/image';
const FeaturedImage = ({ sourceUrl, altText, mediaDetails }) => {
return (
<Image
src={sourceUrl}
alt={altText}
width={mediaDetails.width}
height={mediaDetails.height}
priority // Para imágenes above the fold
/>
);
};
[TIP] Usa priority solo en la imagen principal de la página. Para el resto, Next.js las carga lazy por defecto.
Cacheo Avanzado con GraphQL
Apollo Client tiene un potente sistema de caché. En el servidor, puedes usar la política cache-first o network-only según necesites. Pero para rendimiento frontend extremo, combínalo con el almacenamiento en caché de Next.js.
Puedes usar la función fetch nativa de Next.js con next: { revalidate } en lugar de Apollo Client para peticiones GraphQL. Esto te da control total sobre la caché a nivel de framework.
Ejemplo con fetch nativo:
export default async function Page() {
const query = `
query {
posts {
nodes {
title
slug
}
}
}
`;
const res = await fetch(process.env.NEXT_PUBLIC_WORDPRESS_URL + '/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
next: { revalidate: 60 }, // ISR con fetch nativo
});
const { data } = await res.json();
// ...
}
Despliegue y Monitorización
Para un rendimiento frontend óptimo, despliega en plataformas que soporten Edge Functions y ISR. Las mejores opciones son:
- Vercel (de los creadores de Next.js): Soporte nativo para ISR, Edge Functions y análisis de rendimiento.
- Netlify: También compatible con Next.js 15, aunque con algunas limitaciones en ISR avanzado.
Una vez desplegado, monitoriza con herramientas como:
- Lighthouse para auditorías de rendimiento.
- Vercel Analytics o Google Analytics 4 para ver tiempos de carga reales.
- Web Vitals para Core Web Vitals (LCP, FID, CLS).
Conclusión: El Futuro es Headless
La combinación de headless WordPress, Next.js 15 y GraphQL no es una moda pasajera. Es la respuesta a la necesidad de rendimiento frontend extremo sin sacrificar la flexibilidad de WordPress como CMS. Con SSR para datos dinámicos, SSG para páginas estáticas e ISR para lo que está en el medio, tienes un arsenal completo.
El verdadero poder está en la granularidad. Puedes tener una página de inicio 100% estática, un blog con ISR de 60 segundos y una sección de usuario con SSR, todo en el mismo proyecto. Y con la optimización de imágenes y el cacheo inteligente, tu sitio volará.
No esperes a que tu sitio tradicional de WordPress se caiga por un pico de tráfico. Migra a headless, y verás cómo el rendimiento frontend se dispara.
[INFO] ¿Quieres profundizar? El repositorio oficial de Next.js tiene ejemplos con WordPress. Busca with-wordpress en GitHub.
