Contenido dinámico con Markdown y MDX
1. ¿Qué es Markdown? #
Markdown es un formato de texto plano que se usa para escribir contenido con formato sin usar HTML directamente. Es muy usado en GitHub, blogs y documentación.
Ejemplo:
1# Título principal 2## Subtítulo 3**negrita**, *cursiva*, [enlace](https://astro.build) 4 5- Elemento 1 6- Elemento 2 7- Elemento 3
Astro convierte automáticamente este texto en HTML optimizado.
2. Estructura típica de un blog en Astro #
Puedes crear un blog solo con Markdown:
src/
├── pages/
│ ├── index.astro
│ └── blog/
│ └── [slug].astro
└── content/
└── posts/
├── primer-post.md
└── segundo-post.md
3. Crear un post Markdown #
Crea un archivo en:
src/content/posts/primer-post.md
1--- 2title: "Mi primer post con Astro" 3date: "2025-10-06" 4author: "Ángel González" 5tags: ["astro", "markdown"] 6--- 7 8¡Hola! 9Este es mi **primer post** creado con *Astro*. 10Markdown me permite escribir de forma rápida, simple y elegante.
🧩 Lo que está entre las líneas --- se llama frontmatter: son metadatos que Astro puede leer (como el título o la fecha).
4. Activar el soporte para contenido en Astro #
Astro 3+ ya incluye un sistema integrado llamado Content Collections. Te permite definir tipos de contenido y validarlos.
Paso 1. Crea el esquema #
Crea el archivo:
src/content/config.ts
1import { z, defineCollection } from "astro:content"; 2 3const posts = defineCollection({ 4 schema: z.object({ 5 title: z.string(), 6 date: z.string(), 7 author: z.string().optional(), 8 tags: z.array(z.string()).optional(), 9 }), 10}); 11 12export const collections = { posts };
💡 Esto le dice a Astro qué estructura deben tener los archivos Markdown.
Paso 2. Importar los posts #
En tu página src/pages/blog.astro:
1--- 2import { getCollection } from 'astro:content'; 3const posts = await getCollection('posts'); 4--- 5 6<h1>Blog</h1> 7 8<ul> 9 {posts.map(post => ( 10 <li> 11 <a href={`/blog/${post.slug}`}>{post.data.title}</a> 12 <small>({post.data.date})</small> 13 </li> 14 ))} 15</ul>
✅ getCollection('posts') lee automáticamente todos los .md de la carpeta /posts.
5. Crear la página de detalle de cada post #
Crea una página dinámica:
src/pages/blog/[slug].astro
1--- 2import { getCollection } from 'astro:content'; 3 4// 1. Genera las rutas estáticas durante el build 5export async function getStaticPaths() { 6 const posts = await getCollection('posts'); 7 return posts.map((post) => ({ 8 params: { slug: post.slug }, 9 props: { post }, 10 })); 11} 12 13// 2. Obtiene los datos del post y compila el contenido Markdown 14const { post } = Astro.props; 15const { Content } = await post.render(); 16--- 17 18<html lang="es"> 19 <body> 20 <article> 21 <h1>{post.data.title}</h1> 22 <p><em>{post.data.date}</em></p> 23 <Content /> 24 </article> 25 </body> 26</html>
💡 await post.render() compila el cuerpo del Markdown a un componente <Content /> listo para renderizarse como HTML.
Resultado:
Cada post tiene su propia URL
👉 /blog/primer-post
6. Qué es MDX y por qué usarlo #
MDX es una versión avanzada de Markdown que permite incluir componentes de Astro o React directamente dentro del texto.
Ejemplo:
src/content/posts/post-mdx.mdx
1--- 2title: "Post interactivo con MDX" 3date: "2025-10-06" 4--- 5 6# ¡Hola desde MDX! 7 8Puedes incluir componentes de Astro dentro del contenido: 9 10<Counter start={5} />
src/components/Counter.astro
1--- 2const { start = 0 } = Astro.props; 3let count = start; 4--- 5 6<button id="btn">Count: {count}</button> 7 8<script> 9 let n = {count}; 10 document.getElementById("btn").addEventListener("click", () => { 11 n++; 12 document.getElementById("btn").textContent = "Count: " + n; 13 }); 14</script>
🎉 Así puedes tener contenido interactivo dentro de tus artículos.
7. Integrar Markdown y MDX juntos #
Instala el soporte MDX:
1npx astro add mdx
Esto permite que Astro reconozca .mdx junto con .md.
Ambos se comportan igual, solo que MDX te da la opción de incluir componentes.
8. Organizar tus contenidos #
Estructura sugerida:
src/content/
├── posts/
│ ├── post1.md
│ ├── post2.mdx
│ └── post3.md
├── tutorials/
│ ├── intro.mdx
│ └── avanzado.mdx
└── config.ts
Puedes tener múltiples colecciones (blog, tutoriales, proyectos…).
9. Mostrar etiquetas y metadatos #
Puedes acceder a todos los datos del frontmatter:
1{posts.map(post => ( 2 <li> 3 <a href={`/blog/${post.slug}`}>{post.data.title}</a> 4 <p>Autor: {post.data.author}</p> 5 <small>Etiquetas: {post.data.tags?.join(", ")}</small> 6 </li> 7))}
10. Ventajas de usar Markdown/MDX en Astro #
- ✅ No necesitas base de datos.
- ✅ El contenido se genera automáticamente.
- ✅ Puedes escribir artículos fácilmente sin código complejo.
- ✅ MDX permite mezclar texto y componentes dinámicos.
- ✅ Excelente para blogs, documentación y portfolios.
Resumen del tema
Conceptos clave #
- Colecciones de contenido (
src/content/): sistema nativo para organizar, tipar y validar archivos.mdy.mdx. - Validación con esquemas Zod (
src/content/config.ts): uso dedefineCollectionyz.object()para asegurar tipos consistentes en los metadatos del frontmatter (title,date,tags). - Acceso tipado con
getCollection: consulta asíncrona de entradas en tiempo de compilación con autocompletado y seguridad de tipos (post.data.*). - Páginas dinámicas (
[slug].astro): generación automática de rutas individuales leyendo el identificador único del post (post.slug). - Soporte MDX (
@astrojs/mdx): capacidad de importar y renderizar componentes interactivos de Astro, React o Svelte directamente en el cuerpo del artículo.
Qué debes recordar #
Usa Content Collections con esquemas Zod para gestionar contenido en Markdown/MDX de forma estructurada y validada sin requerir bases de datos.