wandres.dev
SERVER ISLANDS · server:defer y fallback

El contenido fallback mientras la isla se resuelve

Entre que la página estática se pinta y que la server island llega desde el servidor hay un instante en el que el hueco necesita algo que mostrar. El slot=fallback define ese marcador provisional: un esqueleto, un valor por defecto plausible o una red de seguridad que sobrevive incluso sin JavaScript. Diseñar bien esa espera es diseñar una página coherente en sus dos fases.

⏱ 14 min

Una server island no aparece instantáneamente. La página estática se pinta primero y, un momento después, llega el fragmento renderizado por el servidor. Entre ambos instantes el hueco está vacío, y ese vacío hay que llenarlo con algo: un esqueleto, un texto tenue, un valor por defecto razonable. Astro reserva para ello un slot con nombre reservado, slot="fallback", y la calidad de lo que pongas ahí decide si la transición se siente como una página que respira o como una que da un tirón. El fallback no es un detalle de carga: es la primera de las dos verdades que la página cuenta.

🎯 Al terminar esta lección sabrás
  • Entender por qué el hueco de una isla necesita contenido provisional.
  • Usar slot="fallback" para declarar ese marcador dentro del componente diferido.
  • Diseñar la espera: esqueleto, valor por defecto plausible o ausencia deliberada.
  • Ver el fallback como red de seguridad ante JavaScript lento o ausente.

El hueco necesita algo mientras tanto

Recuerda la secuencia del apartado anterior: el navegador recibe el HTML estático, lo pinta, y solo entonces pide la isla al servidor. Ese segundo viaje toma tiempo —una ida y vuelta de red, más lo que tarde el servidor en renderizar—. Durante esos milisegundos, ¿qué ocupa el lugar de la isla?

Si no dices nada, el lugar queda vacío: un salto visible cuando el fragmento real irrumpe y desplaza lo que había debajo. Ese salto es exactamente el CLS que los niveles de rendimiento te enseñaron a temer.

El fallback existe para evitarlo: es el contenido que viaja dentro del HTML estático, se pinta al instante junto al resto de la página y se mantiene en su sitio hasta que la isla llega y lo sustituye.

Piensa en la magnitud del intervalo. En una red rápida, el fallback vive unas pocas decenas de milisegundos y casi no se percibe; en una conexión móvil pobre o con un servidor de borde en arranque en frío, puede durar cientos.

El fallback no es, por tanto, un adorno para el caso ideal: es lo que gobierna la experiencia en el caso real, el del usuario con mala cobertura, que es precisamente a quien más le importa que la página no dé bandazos.

ℹ️
El fallback es estático y cacheable

Lo que pones en el fallback forma parte del HTML horneado de la página. Se cachea con ella, se pinta en el primer paint y no depende de ninguna petición. Por eso está disponible antes que nada: es la capa base sobre la que la isla, más tarde, escribe la versión definitiva.

slot=“fallback”: el marcador visible

El mecanismo reutiliza los slots con nombre del nivel 5. Cualquier elemento que pongas como hijo del componente diferido con el atributo slot="fallback" se convierte en el marcador que se muestra mientras la isla se resuelve.

---
import CarritoResumen from '../components/CarritoResumen.astro';
---
<CarritoResumen server:defer>
  <span slot="fallback" class="carrito-esqueleto">Carrito</span>
</CarritoResumen>

Cuando el fragmento real del servidor llega, Astro reemplaza el nodo del fallback por el HTML de la isla. Todo lo que no lleve slot="fallback" se trata como contenido normal de la isla y se renderiza en el servidor, no en la fase estática.

La separación es limpia: slot="fallback" es lo provisional e inmediato; lo demás es lo definitivo y diferido.

📝
Un slot con un contrato especial

fallback no es un slot con nombre cualquiera: Astro lo interpreta como “muéstrame esto hasta que la isla resuelva”. Si omites el fallback, el hueco simplemente no muestra nada hasta que llega el fragmento, con el consiguiente riesgo de salto. Declararlo es opcional para el compilador, pero casi obligatorio para una buena experiencia.

Diseñar la espera: esqueleto, defecto plausible o nada

Hay tres estrategias, y elegir bien es una decisión de diseño, no de programación.

💀

Esqueleto

Una silueta gris del contenido futuro, con sus mismas dimensiones. Comunica “algo viene aquí” sin prometer un valor concreto. Ideal para tarjetas y listas.

🎯

Defecto plausible

Un valor estático razonable que la isla luego confirma o corrige: Iniciar sesión que se vuelve el menú de tu cuenta. Suele ser la mejor opción.

🫥

Nada deliberado

Un hueco reservado pero vacío, cuando mostrar algo provisional confundiría más que ayudar. Reserva el espacio para no saltar.

La regla de oro es minimizar la distancia perceptual entre las dos fases. Un esqueleto que ocupa el mismo tamaño que el contenido real evita el salto de layout.

Un defecto plausible —el Iniciar sesión que se convierte en tu avatar— evita incluso la sensación de carga, porque la página ya era coherente antes de que la isla llegara. Lo peor es un fallback que difiere en tamaño o significado de lo que lo sustituye: ahí la transición se siente como un parpadeo o un tirón.

<MenuUsuario server:defer>
  <!-- Defecto plausible: la pagina ya tiene sentido asi -->
  <a slot="fallback" href="/login">Iniciar sesión</a>
</MenuUsuario>

Hay un matiz de honestidad en el defecto plausible. No debe mentir sobre el estado final: si a menudo el resultado contradice de plano al fallback —un “carrito vacío” que casi siempre se vuelve “3 artículos”—, el parpadeo semántico molesta más que un esqueleto neutro.

La elección entre esqueleto y defecto plausible depende, entonces, de cuánta certeza tienes sobre el resultado: si el estado más probable es predecible, anticípalo; si es imprevisible, no prometas nada y limítate a reservar el espacio.

Un esqueleto que reserva el mismo espacio que el contenido real es la forma más fiable de que el swap no salte:

<Producto server:defer>
  <!-- Esqueleto con las dimensiones del contenido real -->
  <div slot="fallback" class="tarjeta" aria-hidden="true">
    <div class="linea-titulo"></div>
    <div class="linea-precio"></div>
  </div>
</Producto>
💡
Marca el esqueleto como decorativo

Un esqueleto es ruido para un lector de pantalla. Márcalo con aria-hidden="true" para que no anuncie líneas vacías; el contenido real, cuando llega, trae su propia semántica.

flowchart LR
A[primer paint muestra el fallback] --> B[el navegador pide la isla]
B --> C[llega el fragmento del servidor]
C --> D[swap sin salto de layout]
style A fill:#f9e2af,color:#11111b
style C fill:#89b4fa,color:#11111b
style D fill:#a6e3a1,color:#11111b

El fallback como red de seguridad

Hay una propiedad del fallback que va más allá de la estética de carga. Como forma parte del HTML estático, sigue ahí aunque la isla nunca llegue: si el JavaScript falla, si la red del segundo viaje se cae, si un lector automático no ejecuta la petición diferida, lo que queda en pantalla es el fallback.

Eso convierte la elección del fallback en una decisión de resiliencia: es el estado terminal de la página cuando lo dinámico no se materializa.

De ahí que un buen fallback deba ser aceptable por sí mismo, no solo como paso intermedio. Un Iniciar sesión es un estado terminal digno: si la isla del menú de usuario nunca resuelve, el visitante ve una página perfectamente usable. Un esqueleto gris permanente, en cambio, es un estado terminal roto.

Diseña el fallback pensando “¿y si esto es lo único que se ve?”, no solo “¿y si esto se ve un instante?”.

Esta doble lectura conecta con la mejora progresiva que recorre toda la web bien construida: la capa base debe funcionar sola, y las capas superiores solo la refinan. El fallback es tu capa base.

Un rastreador que no ejecuta la segunda petición indexará el fallback; un navegador con JavaScript desactivado mostrará el fallback; una función serverless que agota su tiempo dejará el fallback.

En los tres casos, la pregunta es la misma: ¿es ese estado suficientemente bueno? Si la respuesta es sí, tu isla es robusta; si es no, has escondido contenido esencial detrás de un viaje que no siempre ocurre.

Los estados en los que el fallback es lo único que hay:

  • El rastreador que no sigue la segunda petición: indexa el fallback.
  • El navegador sin JavaScript: se queda en el fallback.
  • La función que agota su tiempo o falla: deja el fallback como desenlace.
  • La red que se corta a mitad del segundo viaje: el fallback permanece.
⚠️
No metas contenido crítico solo en la isla

Si un dato debe verse siempre —y sobre todo si importa para SEO—, no puede vivir únicamente en la server island, porque la isla llega después del HTML inicial y puede no llegar nunca. El fallback es tu garantía mínima: lo que pongas ahí es lo que el mundo verá con certeza. Lo veremos con detalle en la lección de límites.

El fallback es la verdad provisional de una página que se cuenta en dos fases

Una server island parte la vida de una página en dos momentos, y cada momento carga con una verdad distinta. La fase estática lleva una verdad provisional y universal: lo que es cierto para cualquiera antes de saber quién mira —“aquí hay un menú”, “aquí va un precio”—. La fase diferida lleva la verdad definitiva y particular: tu menú, el precio de este segundo. El fallback es la forma que le das a esa primera verdad, y diseñarlo bien significa aceptar que tu página tiene que ser correcta y coherente en ambos estados, no solo en el final. Debe tener sentido como HTML puro —para el primer pintado, para quien no ejecuta JavaScript, para el rastreador que no sigue la segunda petición— y luego refinarse hacia lo personal sin contradecirse de golpe. Esto es la mejora progresiva llevada a su conclusión más exigente: no “una base que funciona y unos extras que adornan”, sino dos capas de verdad cuya distancia —de tamaño, de significado, de tono— es lo que el usuario percibe como fluidez o como brusquedad. Y hay una simetría profunda con las islas de cliente: allí el HTML del servidor era el fallback de la hidratación, la versión que se veía antes de que el JavaScript cobrara vida; aquí el fallback estático es la versión que se ve antes de que el servidor responda. En ambos casos, el arte no está en la capa rica que llega después, sino en cuán completa y digna es la capa pobre que llega primero. El desarrollador que interioriza esto deja de tratar el fallback como un spinner de relleno y empieza a tratarlo como lo que es: el contrato mínimo que su página cumple pase lo que pase.

⚔️ Diseña las dos fases de una isla
  1. Crea una server island para un contador de “me gusta” con server:defer y dale un fallback con un valor por defecto plausible, no un spinner.
  2. Ajusta el fallback para que ocupe exactamente las dimensiones del contenido real y verifica que el CLS no se dispara al hacer el swap.
  3. Estrangula la red en las herramientas del navegador y observa cuánto tiempo vive el fallback y cómo se siente la transición.
  4. Desactiva JavaScript y confirma que el fallback, por sí solo, deja la página coherente y usable.
  5. Busca en tu proyecto una isla cuyo fallback sea un esqueleto vacío y decide si un defecto plausible la mejoraría o si el resultado es demasiado imprevisible para anticiparlo.