¿Qué hace Astro Islands Architect?
Astro es "envía HTML por defecto, hidrata solo lo que necesita JS". Para sitios de marketing, documentación y con mucho contenido, esto produce bundles dramáticamente más pequeños que React/Next.js. El objetivo es elegir qué componentes son estáticos y cuáles son islas.
Cuándo usarlo
- Sitio de marketing, blog, portal de documentación — el contenido es el producto.
- Migración desde un sitio de marketing en Next.js que tiene un JS de cliente pesado.
- Multi-framework — una librería de componentes React usada junto con componentes Vue o Svelte.
- Autoría de contenido pesado con MDX + frontmatter con tipos seguros.
- Transiciones de vista entre páginas sin un SPA.
Capacidades principales
Estructura de página
---
// src/pages/blog/[slug].astro — el frontmatter se ejecuta en tiempo de build/SSR
import { getCollection, getEntry } from 'astro:content';
import Layout from '../../layouts/Default.astro';
import Newsletter from '../../components/Newsletter.tsx';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((p) => ({ params: { slug: p.slug }, props: { post: p } }));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<Layout title={post.data.title}>
<h1>{post.data.title}</h1>
<article><Content /></article>
{/* Isla — solo este componente envía JS */}
<Newsletter client:visible />
</Layout>
Los delimitadores --- son código de servidor. Dentro de <...>, el valor predeterminado es HTML estático. Los componentes con directivas client:* se convierten en islas.
Directivas de cliente — elige la correcta
| Directiva | Cuándo se hidrata | Úsalo para |
|---|---|---|
client:load | Carga de página | Interactivo sobre el pliegue (carrito, búsqueda). |
client:idle | Cuando el navegador está inactivo | Interactivo no crítico (widget de chat). |
client:visible | Cuando se desplaza al viewport | Debajo del pliegue (suscripción a newsletter, comentarios). |
client:media="(min-width: 768px)" | Cuando la media query coincide | Widgets solo para escritorio. |
client:only="react" | Omitir SSR; renderizado solo del lado del cliente | Componentes que necesitan APIs del navegador al montarse. |
client:idle es el valor predeterminado correcto para la mayoría de las islas no críticas. client:load es el martillo pesado; resérvalo.
Colecciones de contenido
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content', // archivos markdown/MDX
schema: z.object({
title: z.string().max(120),
description: z.string().max(160),
date: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
cover: z.object({ src: z.string(), alt: z.string() }).optional(),
}),
});
export const collections = { blog };
Ahora getCollection('blog') está completamente tipado. Los errores de frontmatter fallan en el build, no en producción.
const posts = (await getCollection('blog'))
.filter((p) => !p.data.draft)
.sort((a, b) => +b.data.date - +a.data.date);
Multi-framework
npx astro add react vue svelte
---
import ReactSearch from '../components/Search.tsx';
import VueChart from '../components/Chart.vue';
import SvelteToggle from '../components/Toggle.svelte';
---
<ReactSearch client:idle />
<VueChart client:visible />
<SvelteToggle client:load />
El runtime de cada framework se empaqueta por separado y se carga solo en las páginas que lo usan. Para un sitio de documentación mayormente estático, esto puede significar enviar cero JS de React a la mayoría de las páginas.
Islas de servidor (Astro 4+)
<Layout>
<Header />
<PersonalizedRecommendations server:defer>
<p slot="fallback">Cargando recomendaciones...</p>
</PersonalizedRecommendations>
<Footer />
</Layout>
server:defer renderiza el resto de la página inmediatamente y transmite el HTML del componente diferido a través de una solicitud separada. Útil para contenido personalizado que de otro modo forzaría a toda la página a ser SSR.
Optimización de imágenes
---
import { Image } from 'astro:assets';
import cover from '../assets/cover.jpg';
---
<Image src={cover} alt="Foto de portada" widths={[400, 800, 1200]} sizes="(max-width: 768px) 400px, 1200px" />
Astro genera srcset, ejecuta Sharp para redimensionar y envía solo lo necesario. Coloca las imágenes bajo src/assets/ para una optimización completa; public/ no se procesa.
Transiciones de vista
---
import { ViewTransitions } from 'astro:transitions';
---
<html>
<head>
<ViewTransitions />
</head>
...
</html>
<a href="/about" transition:name="hero">Acerca de</a>
Transiciones entre páginas sin un SPA. El navegador hace la mayor parte del trabajo; Astro coordina la coincidencia de elementos.
MDX con componentes
---
title: Mi artículo
date: 2026-04-30
---
import Callout from '../../components/Callout.astro';
# {frontmatter.title}
<Callout type="warn">
Esto es una advertencia renderizada del lado del servidor. Sin JS.
</Callout>
Los componentes importados en MDX se ejecutan en tiempo de build/SSR a menos que sean islas.
SSR híbrido
// astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'hybrid',
adapter: cloudflare(),
});
---
// src/pages/api/search.ts — se ejecuta en el edge
export const prerender = false;
export async function GET({ request }) {
const url = new URL(request.url);
const q = url.searchParams.get('q') ?? '';
const results = await search(q);
return new Response(JSON.stringify(results), { headers: { 'content-type': 'application/json' } });
}
prerender = false opta a una ruta a SSR; el resto del sitio permanece estático.
Anti-patrones
client:load en todas partes
Síntoma: El bundle de JS de Lighthouse se infla; la historia de hidratación de Astro desaparece.
Diagnóstico: Los ingenieros usan client:load por defecto porque es lo más familiar.
Solución: Usa client:idle o client:visible por defecto. Reserva client:load para elementos interactivos sobre el pliegue.
Obtener datos en componentes del cliente
Síntoma: Spinners de carga en cada página; el SEO se ve afectado.
Diagnóstico: La obtención de datos se movió a componentes React en lugar del frontmatter de Astro.
Solución: Obtén los datos en los delimitadores ---, renderiza del lado del servidor, pasa los datos como props a las islas.
Frontmatter sin tipo
Síntoma: El build tiene éxito; producción muestra undefined en los títulos.
Diagnóstico: No hay esquema de colección de contenido; un error tipográfico en frontmatter pasó desapercibido.
Solución: Usa defineCollection con un esquema zod. Los errores de frontmatter fallan en el build.
Mezclar public/ y src/assets/ para imágenes
Síntoma: Algunas imágenes optimizadas, otras se envían en su tamaño original.
Diagnóstico: public/ se sirve tal cual; solo src/assets/ pasa por Sharp.
Solución: Mueve las imágenes a src/assets/. Usa <Image> en todos lados. public/ solo para imágenes OG y favicons.
Intentar usar Astro para un SPA
Síntoma: Batalla constante con la hidratación; las islas crecen hasta que toda la página es interactiva. Diagnóstico: Framework incorrecto para el trabajo. Astro brilla para contenido; los SPA necesitan Next/Remix. Solución: Usa Next/Remix cuando la mayoría de las páginas sean interactivas. Usa Astro para marketing y documentación.
Uso excesivo de client:only
Síntoma: Desplazamiento de diseño (CLS) en cada carga de página; "parpadeo" antes de que aparezca el contenido.
Diagnóstico: Omitir SSR significa que el navegador ve un placeholder vacío hasta que se ejecuta el JS.
Solución: Usa client:only solo cuando el componente realmente no pueda renderizarse del lado del servidor. Proporciona un placeholder que se aproxime al tamaño final.
Puertas de calidad
- La directiva de cliente predeterminada es
client:idleoclient:visible;client:loadjustificado por uso. - Todo el contenido tiene un esquema tipado mediante
defineCollection. - Las imágenes están bajo
src/assets/y usan el componente<Image>. - Las integraciones multi-framework (
@astrojs/react, etc.) se agregaron solo para componentes que existen. - LCP menor de 2s en la página representativa más lenta.
- Presupuesto de JS de primera carga establecido por página; CI falla en regresiones.
- MDX usa componentes de Astro para partes estáticas; islas solo donde sea interactivo.
- Transiciones de vista probadas en las rutas de navegación principales.
NO para
- SPA completos — Next.js, Remix, TanStack Start son mejores opciones.
- Creación de plugins/integraciones de Astro — skill separado (aún no hay skill dedicado).
- Ajustes de build del lado de Vite — Astro usa Vite internamente. →
vite-build-optimizerpara tamaño de chunks, HMR, problemas del ciclo de vida de plugins. - Aplicaciones con mucho estado del cliente (paneles de control, herramientas en tiempo real) — demasiado JS para que las islas ayuden.
- Móvil nativo — Astro es solo web.