La estructura de directorios
La anatomía de un proyecto Astro: src/pages y public son las dos carpetas con significado especial; src/components, src/layouts, src/content y src/styles son convención. Qué va exactamente en cada sitio y por qué.
El árbol de un proyecto
Tras el andamiaje, un proyecto mínimo tiene esta forma. En la raíz viven los ficheros de configuración; dentro de src vive tu código; public guarda lo estático sin procesar.
En azul, las dos carpetas que Astro trata de forma especial; en verde, src, el contenedor de todo lo que Vite procesa. La distinción no es estética: define qué ocurre con cada fichero cuando construyes el sitio.
En la raíz, fuera de src, viven los ficheros que gobiernan el proyecto entero: astro.config.mjs con la configuración, package.json con dependencias y scripts, y tsconfig.json con los ajustes de TypeScript. No contienen páginas ni componentes; describen cómo se comporta todo lo demás. Conviene tenerlos localizados desde el principio, porque a ellos volverás cada vez que añadas una integración o cambies el modo de renderizado.
src/pages: la única carpeta que enruta
src/pages es el corazón del framework. Astro aplica aquí enrutado por ficheros: cada archivo se convierte en una ruta según su ruta relativa. No hay que declarar rutas en ningún sitio; la estructura del sistema de ficheros es el mapa de URLs.
src/pages/index.astrogenera la raíz, la URL/.src/pages/blog/index.astrogenera/blog.src/pages/blog/primer-post.astrogenera/blog/primer-post.
Admite varios formatos como páginas: .astro, .md, .mdx y .html producen páginas; los ficheros .js y .ts producen endpoints —respuestas de API en vez de HTML—. Fuera de src/pages, ninguno de esos ficheros crea una ruta.
El enrutado también entiende parámetros. Un nombre de fichero entre corchetes captura un segmento dinámico, y uno con puntos suspensivos captura varios de golpe:
src/pages/blog/[slug].astroresponde a/blog/lo-que-sea.src/pages/docs/[...ruta].astroresponde a/docs/con/varios/niveles.
Esta misma guía se sirve así: una sola plantilla dinámica genera cientos de lecciones leyendo las colecciones de contenido. Verás el enrutado dinámico a fondo más adelante; por ahora basta con saber que los corchetes en src/pages son la puerta a rutas generadas por datos.
La contrapartida de esa comodidad es una disciplina: no dejes ficheros sueltos en src/pages que no sean páginas. Cualquier .astro que aterrice ahí se convierte en una URL pública, casi siempre una que no querías exponer. Los componentes auxiliares viven en src/components, nunca en src/pages.
src/components, layouts y styles: convención útil
El resto de carpetas dentro de src no significan nada especial para Astro: son nombres que la comunidad acordó para ordenar el código. Podrías renombrarlas y todo seguiría funcionando siempre que ajustaras tus imports. Aun así, respétalas: la convención compartida es lo que hace que cualquiera entienda tu proyecto de un vistazo.
Un layout es solo un componente que coloca un <slot /> donde irá el contenido de cada página que lo use:
---// src/layouts/Base.astroconst { titulo } = Astro.props;---<html lang="es"> <head><title>{titulo}</title></head> <body> <slot /> </body></html>Ese <slot /> es el hueco; una página envuelve su contenido con el layout y aparece ahí. Es toda la mecánica que separa src/layouts de src/components: intención, no magia del framework.
Como estas carpetas no son mágicas, eres libre de anidarlas y co-localizar: agrupar un componente con su estilo y su test en una subcarpeta, o crear src/features con módulos completos. Astro no impone jerarquía; solo te pide que las páginas encuentren lo que importan.
La clave mental es que todo lo que vive en src pasa por el pipeline de Vite: se analiza, se agrupa, se optimiza y se le añade un hash al nombre para cachearlo con seguridad. Por eso una imagen importada desde src/assets puede optimizarse y transformarse, mientras que una imagen en public sale intacta.
src/content y public: contenido y estáticos
src/content es la carpeta convencional para tus colecciones de contenido: el Markdown y el MDX de tu blog, tus docs o tu catálogo. Las colecciones se declaran en src/content.config.ts, donde defines un esquema tipado con Zod; a partir de ahí tu frontmatter tiene tipos y autocompletado. Verás las colecciones a fondo más adelante; por ahora, quédate con que esta carpeta es el hogar natural del contenido estructurado. Desde la Content Layer, el contenido incluso puede vivir fuera de src/content o venir de una fuente remota; la carpeta es una convención cómoda, no una obligación del framework.
mi-proyecto/├─ src/│ ├─ pages/ rutas del sitio (especial)│ ├─ components/ UI reutilizable (convencion)│ ├─ layouts/ plantillas de pagina (convencion)│ ├─ content/ colecciones md y mdx (convencion)│ └─ styles/ css global (convencion)├─ public/ servido tal cual (especial)├─ astro.config.mjs configuracion del proyecto├─ tsconfig.json configuracion de typescript└─ package.json dependencias y scriptsEse árbol condensa la regla entera: junto a cada carpeta, si es especial o convención. Interiorizar esa columna te ahorra consultar la documentación cada vez que dudes dónde poner algo.
public, en cambio, es la otra carpeta especial. Todo lo que pongas dentro se copia sin tocar a la raíz del sitio publicado: public/favicon.svg acaba en /favicon.svg, public/robots.txt en /robots.txt. Ni bundling, ni hash, ni optimización. Es el sitio para ficheros que deben conservar su nombre y ruta exactos: el favicon, el robots.txt, el manifest, fuentes que sirves crudas o verificaciones de dominio.
Con el tiempo verás aparecer tres carpetas más que no creaste tú y que no debes tocar: node_modules con las dependencias, dist con el resultado del build, y .astro con los tipos generados. Las tres son artefactos regenerables y van al .gitignore. Reconocerlas evita el susto de creer que forman parte de tu código fuente.
Con estas piezas ya tienes el mapa completo: sabes qué genera rutas, qué se copia intacto, qué procesa Vite y qué es solo convención. Es suficiente para moverte por cualquier proyecto Astro sin perderte y para colocar cada fichero nuevo en su sitio a la primera.