Why NextWhy Next
Volver a la lista
💻 Desarrollo3 min de lectura

Crear un blog MDX con Next.js desde cero: así construí este blog

El proceso de crear con Next.js 16 App Router un blog que funciona solo con archivos Markdown, sin CMS. Estructura de carpetas, configuración de MDX y SEO, explicado con el flujo de código real.

Lo esencial

Si guardas los artículos como archivos .mdx bajo src/content/posts y los renderizas con @next/mdx, el blog funciona sin CMS. El archivo es la URL, y en vez de frontmatter se usa un meta export para generar el listado y los metadatos.

En esta página

Este blog que estás leyendo no tiene base de datos ni panel de administración. Cada artículo es un solo archivo Markdown. Aquí te cuento exactamente cómo lo construí.

Por qué basado en archivos

Hay muchas herramientas para blogs, pero para un desarrollador independiente la mayoría son excesivas.

  • CMS: trae consigo panel de administración, integraciones y facturas
  • Integración con Notion: cómoda, pero te topas con límites en renderizado, velocidad y personalización
  • Archivos Markdown: los artículos se versionan con el código, es gratis, y git push equivale a publicar

Yo elegí la tercera opción. Es la que menos fricción tiene.

Estructura de carpetas

Si nos quedamos con lo esencial, se ve así.

src/
├── app/
│   ├── page.tsx              # 홈 - 글 목록
│   ├── posts/[slug]/page.tsx # 글 상세
│   └── sitemap.ts            # /sitemap.xml
├── content/posts/*.mdx       # ← 글은 여기에만 추가
└── lib/posts.ts              # 목록·메타 로딩

El nombre del archivo se convierte en la URL. hello.mdx se abre en /posts/hello.

Configuración de MDX

Para usar MDX con App Router se añade @next/mdx. Como Next 16 usa Turbopack por defecto, los plugins de remark/rehype hay que pasarlos como nombres en string (no se pueden pasar referencias a funciones).

const withMDX = createMDX({
  options: {
    remarkPlugins: ["remark-gfm"],   // 표·취소선 지원
    rehypePlugins: ["rehype-slug"],  // 제목 앵커
  },
})

meta export en vez de frontmatter

Normalmente el título y la fecha van en el bloque --- (frontmatter) al inicio del Markdown, pero como MDX puede contener JavaScript, hay una forma más limpia: simplemente exportar un objeto.

export const meta = {
  title: "글 제목",
  date: "2026-07-06",
  category: "dev",
}

## 본문 시작

En la página de listado se hace un import dinámico de cada archivo y se lee solo ese meta.

const mod = await import(`@/content/posts/${slug}.mdx`)
return mod.meta   // 본문 렌더 없이 메타만

No hacen falta librerías de parseo ni índices aparte.

SEO desde el primer día

Si el objetivo del blog es atraer visitas, el SEO no va al final sino al principio. Yo dejé listos desde el inicio los metadatos por artículo, Open Graph, datos estructurados JSON-LD, y también sitemap.xml, robots.txt y rss.xml. De esto hablaré con más detalle en el próximo artículo.

En resumen

  • Cada artículo es un archivo .mdx, y el nombre del archivo es la URL
  • @next/mdx + plugins como strings (Turbopack)
  • export const meta en vez de frontmatter
  • SEO desde el primer commit

Con esta misma estructura puedes levantar tu blog en 30 minutos. Yo la uso para seguir acumulando historias de productos como La Ola del Día.

Preguntas frecuentes

¿Por qué usar archivos MDX en vez de un CMS?

Los artículos se versionan junto con el código, es gratis y desplegar equivale a publicar, así que es la opción con menos fricción para un desarrollador independiente. Además puedes insertar imágenes, código y componentes con total libertad.

¿Cómo se genera el listado sin frontmatter?

Exportas un objeto meta al inicio de cada .mdx y, en la página de listado, haces un import dinámico del archivo para leer solo ese meta. No necesitas ninguna librería de parseo adicional.

Artículos relacionados