Los mejores CMS para Astro: cómo funcionan
Guía práctica para elegir CMS con Astro: Strapi, AstroAdmin, Payload, Directus y WordPress, con ejemplos reales y criterio de proyecto.

Astro es una maravilla cuando quieres una web rápida, limpia y fácil de desplegar. Pero en cuanto la web la tiene que tocar otra persona, aparece la pregunta de siempre: ¿cómo edita el cliente los textos, las imágenes o las páginas sin abrir Git ni escribir Markdown?
Ahí entra el CMS. Y aquí conviene no dejarse llevar por el nombre más moderno. La pregunta no es solo “cuál es el mejor CMS para Astro”, sino algo bastante más terrenal: cuál encaja con esa web, con ese cliente y con el mantenimiento que vas a poder asumir dentro de seis meses.
| CMS | Mejor para | Conexión con Astro | Cuidado principal |
|---|---|---|---|
| Strapi | Proyectos a medida con modelos claros | REST o GraphQL desde getStaticPaths() y páginas Astro | Hay que alojar Node, base de datos y medios |
| AstroAdmin | Panel propio hecho en Astro | No es CMS completo: tú creas API, auth y persistencia | Puede salir caro si reinventas permisos, media y editor |
| Payload | Equipos técnicos que quieren CMS en TypeScript | REST, GraphQL o Local API si comparte runtime | Muy potente, pero más backend que “panel sencillo” |
| Directus | Datos SQL existentes y panel visual rápido | SDK oficial, REST o GraphQL | Modelar bien permisos y relaciones desde el principio |
| WordPress | Clientes españoles acostumbrados a editar | REST API incluida o WPGraphQL | Mantener WordPress solo como backend, no como frontend pesado |
Primero: qué pinta un CMS en una web Astro
En una web Astro con CMS normalmente tienes dos piezas bien separadas:
- El CMS, donde alguien edita páginas, entradas, imágenes, categorías o fichas.
- Astro, que consulta esos datos y genera la web pública.
Para una web corporativa, portfolio, blog o landing de servicios, lo más habitual es que Astro genere páginas estáticas:
Editor cambia contenido en el CMS
↓
Webhook o deploy manual
↓
Astro consulta la API del CMS durante el build
↓
Se publica HTML estático rápidoLa gracia está en que el visitante no entra al CMS. Entra a una web ya generada, ligera y fácil de cachear. El CMS puede vivir tranquilamente en cms.ejemplo.com, protegido, con su login y sus permisos, sin formar parte de la experiencia pública.
Un patrón básico en Astro sería:
export async function getStaticPaths() {
const posts = await getPosts();
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}Después, la página [slug].astro recibe post y pinta componentes. Lo importante no es solo hacer el fetch, sino decidir qué campos necesitas, cómo gestionas imágenes, qué pasa si falta un dato y cuánto HTML del CMS vas a dejar pasar a la web pública.
Strapi: cuando quieres contenido muy ordenado
Strapi tiene sentido cuando quieres construir una API editorial clara: páginas, posts, servicios, autores, casos de éxito, categorías, testimonios o bloques reutilizables. No es tan familiar para muchos clientes como WordPress, pero cuando el modelo de contenido está bien pensado, se trabaja muy a gusto.
Un modelo realista para una web de servicios podría ser:
pages:title,slug,seoTitle,seoDescription,blocks.services:name,slug,excerpt,content,featuredImage.caseStudies:client,slug,summary,gallery,result.global: teléfono, email, redes, textos del footer.
En Astro guardarías la URL:
STRAPI_URL="https://cms.ejemplo.com"
STRAPI_TOKEN="token-de-lectura"Y crearías un cliente sencillo:
type StrapiParams = Record<string, string>;
export async function getStrapi<T>(endpoint: string, params: StrapiParams = {}) {
const url = new URL(`/api/${endpoint}`, import.meta.env.STRAPI_URL);
Object.entries(params).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
const res = await fetch(url, {
headers: {
Authorization: `Bearer ${import.meta.env.STRAPI_TOKEN}`,
},
});
if (!res.ok) {
throw new Error(`Error consultando Strapi: ${res.status}`);
}
const json = await res.json();
return json.data as T;
}Para listar posts:
const posts = await getStrapi('articles', {
'filters[publishedAt][$notNull]': 'true',
'sort': 'publishedAt:desc',
'populate': 'cover',
});Para una página por slug:
const pages = await getStrapi('pages', {
'filters[slug][$eq]': Astro.params.slug ?? '',
'populate': 'blocks.image',
});
const page = pages[0];Lo bueno de Strapi es que te obliga a pensar el contenido como datos, no como páginas sueltas llenas de apaños. Eso para Astro encaja muy bien. Lo menos cómodo es la parte operativa: necesitas alojar Node, base de datos, backups, permisos, media library y actualizaciones. Para una pyme que solo quiere tocar “Inicio”, “Servicios” y “Contacto”, puede ser demasiado si no hay una razón clara.
AstroAdmin: interesante si necesitas un panel propio
Aquí hay que separar conceptos. AstroAdmin, entendido como panel hecho con Astro o como plantilla de administración, no compite de verdad con Strapi, Payload, Directus o WordPress. No te da por sí solo un gestor editorial maduro con roles, historial, media library, API pública, editor visual y flujos de publicación.
Sí puede tener mucho sentido si necesitas un backoffice propio:
- Panel para revisar leads.
- Gestión interna de pedidos.
- CRUD de recursos privados.
- Panel de reservas.
- Zona de administración para una herramienta a medida.
Pero si lo usas como CMS, tú tienes que construir casi todo:
AstroAdmin
├─ Login
├─ Roles y permisos
├─ Formularios de edición
├─ Validación
├─ Base de datos
├─ Subida de imágenes
├─ API de lectura
└─ Auditoría de cambiosUna ruta API simple en Astro podría guardar entradas en una base de datos:
export const POST = async ({ request }) => {
const body = await request.json();
if (!body.title || !body.slug) {
return new Response('Faltan campos obligatorios', { status: 400 });
}
await db.post.upsert({
where: { slug: body.slug },
update: body,
create: body,
});
return Response.json({ ok: true });
};Luego la web pública leería desde tu propia API o directamente desde la base de datos si usas SSR. Es flexible, pero no es barato en horas. Yo lo elegiría cuando el panel forma parte de una aplicación propia, no como solución rápida para “quiero editar mi web”.
Payload: muy potente si el proyecto ya es técnico
Payload es muy potente si quieres que el CMS viva cerca del código. Defines colecciones en TypeScript, controlas campos, permisos, hooks, relaciones y APIs. No lo veo como “un WordPress moderno para todo”, sino como una base muy seria cuando el proyecto tiene bastante lógica detrás.
Una colección simplificada de páginas podría tener esta pinta:
export const Pages = {
slug: 'pages',
fields: [
{ name: 'title', type: 'text', required: true },
{ name: 'slug', type: 'text', required: true, unique: true },
{
name: 'layout',
type: 'blocks',
blocks: [HeroBlock, TextImageBlock, FaqBlock],
},
{
name: 'seo',
type: 'group',
fields: [
{ name: 'title', type: 'text' },
{ name: 'description', type: 'textarea' },
],
},
],
};Astro puede consultar Payload por REST:
const res = await fetch(
'https://cms.ejemplo.com/api/pages?where[slug][equals]=inicio&depth=2'
);
const data = await res.json();
const page = data.docs[0];Luego renderizas bloques:
---
const { page } = Astro.props;
---
{page.layout.map((block) => {
if (block.blockType === 'hero') {
return <Hero title={block.title} text={block.text} />;
}
if (block.blockType === 'textImage') {
return <TextImage title={block.title} image={block.image} />;
}
return null;
})}Payload brilla cuando el CMS no es solo un sitio donde cambiar textos, sino una parte importante del producto: áreas privadas, permisos complejos, relaciones, formularios, integraciones o lógica editorial avanzada. Para una web pequeña se puede ir de tamaño. Para una plataforma de contenidos o una web corporativa grande, es una base muy sólida.
Directus: cuando la web tiene datos de verdad
Directus me parece especialmente cómodo cuando la web no va de “entradas de blog”, sino de datos: inmuebles, cursos, documentos, eventos, delegaciones, productos, fichas, equipos o cualquier cosa que tenga relaciones claras. Se apoya en SQL y te da un panel visual encima.
Imagina una web de formación con:
courses: título, slug, duración, modalidad, provincia.teachers: nombre, bio, foto.course_categories: familia formativa.landing_pages: textos SEO y bloques.
Con el SDK oficial puedes consultar desde Astro:
import { createDirectus, readItems, rest } from '@directus/sdk';
type Course = {
id: number;
slug: string;
title: string;
modality: string;
};
type Schema = {
courses: Course[];
};
const directus = createDirectus<Schema>('https://cms.ejemplo.com').with(rest());
const courses = await directus.request(
readItems('courses', {
filter: { status: { _eq: 'published' } },
fields: ['id', 'slug', 'title', 'modality'],
sort: ['title'],
})
);Para generar URLs:
export async function getStaticPaths() {
const courses = await directus.request(
readItems('courses', {
filter: { status: { _eq: 'published' } },
fields: ['slug', 'title', 'modality'],
})
);
return courses.map((course) => ({
params: { slug: course.slug },
props: { course },
}));
}Directus me gusta mucho cuando hay datos relacionados y el cliente necesita un panel claro para mantenerlos. El punto delicado está en permisos y relaciones: si dejas todo demasiado abierto, el editor puede romper contenido; si lo cierras demasiado, acabará llamándote para cambios sencillos.
WordPress con Astro: probablemente la opción más realista en España
En España WordPress tiene una ventaja enorme: muchísima gente ya lo ha usado o, como mínimo, lo reconoce. Eso pesa más de lo que parece. Un cliente puede no saber qué es un headless CMS, pero sí entiende una frase como “entras a WordPress y editas la página”.
Con Astro, WordPress cambia de papel:
WordPress tradicional:
WordPress edita + WordPress renderiza + WordPress carga plugins en público
WordPress headless con Astro:
WordPress edita + Astro renderiza + el visitante recibe HTML ligeroLa API REST viene incluida. Para empezar:
const res = await fetch(
'https://cms.ejemplo.com/wp-json/wp/v2/posts?_embed&_fields=slug,title,excerpt,content,_embedded'
);
const posts = await res.json();Para páginas:
const res = await fetch(
'https://cms.ejemplo.com/wp-json/wp/v2/pages?slug=inicio&_embed'
);
const pages = await res.json();
const page = pages[0];Para tipos personalizados, WordPress debe exponerlos en REST:
add_action('init', function () {
register_post_type('rfm_servicio', [
'label' => 'Servicios',
'public' => true,
'show_in_rest' => true,
'supports' => ['title', 'editor', 'thumbnail', 'excerpt'],
'rewrite' => ['slug' => 'servicios'],
]);
});Y Astro los consume:
const res = await fetch(
'https://cms.ejemplo.com/wp-json/wp/v2/rfm_servicio?_embed&per_page=100'
);
const services = await res.json();Si quieres una experiencia más ordenada para el desarrollador, puedes usar WPGraphQL, pero para muchas webs corporativas la REST API basta.
La diferencia frente a una web WordPress clásica es bastante grande. La parte pública ya no tiene que ejecutar el tema, el maquetador, media docena de plugins SEO, plugins de caché, optimizadores, constructores visuales y scripts de terceros en cada visita. Astro genera páginas limpias y WordPress se queda haciendo lo que mejor entiende el cliente: editar contenido.
Esto se nota justo en tres temas que preocupan mucho en webs reales:
Cookies. Si la web pública en Astro no carga Google Analytics, píxeles publicitarios, vídeos embebidos o mapas antes del consentimiento, puedes reducir o incluso evitar el típico banner intrusivo. No es magia legal, porque depende de qué cargues. Pero no arrastras cookies simplemente porque el panel de edición sea WordPress.
SEO. No necesitas pagar un plugin SEO solo para pintar un <title>, una metadescripción, un canonical, Open Graph, sitemap o Schema. Puedes guardar esos campos en WordPress y renderizarlos tú en Astro con control total. El plugin SEO puede seguir ayudando dentro del panel editorial, pero la web pública no depende de él para cargar rápido.
PageSpeed y servidor. Si Astro publica HTML estático, el servidor no tiene que levantar WordPress en cada visita. Eso reduce CPU, consultas SQL, problemas de caché y necesidad de contratar un hosting enorme para que la web tenga buena nota. Para una web corporativa, portfolio, blog o landing de servicios, esta arquitectura puede rendir muy bien con una infraestructura bastante razonable.
El coste está en otra parte: tienes que mapear bien imágenes, enlaces internos, menús, formularios y previews. También debes decidir si WordPress vive en cms.ejemplo.com, si bloqueas la indexación del backend y cómo se lanza el build cuando alguien publica. No es gratis, pero para muchos clientes es una mezcla muy razonable: edición conocida por dentro y web rápida por fuera.
Entonces, cuál elegiría
Mi decisión rápida sería esta:
- Web corporativa para cliente español: WordPress + Astro.
- Contenido estructurado sin herencia WordPress: Strapi.
- Proyecto técnico con mucho TypeScript y permisos: Payload.
- Catálogo o datos relacionales: Directus.
- Panel interno a medida: AstroAdmin, pero sabiendo que no estás eligiendo un CMS terminado.
La mejor arquitectura no es la que suena más moderna en una comparativa. Es la que permite editar sin miedo, desplegar sin dramas y mantener una web rápida cuando pasen los meses.
Documentación útil