Tag: Astro

  • Astro 7.3: el candado que bloqueaba tus tests E2E en preview

    Astro 7.3: el candado que bloqueaba tus tests E2E en preview

    Actualizas Astro. Lanzas la suite de Playwright. Un servidor de preview arranca bien y los demás se caen con un error que no habla de tus tests: habla de un lockfile.

    Tú no habías puesto ningún lockfile. Y el commit de esa noche no tocaba nada de testing.

    Ese error tiene una historia detrás, y la historia no va de ti. Va de los agentes de IA.

    Astro 7.3.0 se publicó el 3 de septiembre de 2026 con tres cambios pequeños: el flag --ignore-lock llega a astro preview, el logger de runtime de Astro se pasa a los image services y cache providers custom, y @astrojs/cloudflare 14.3.0 incorpora un helper finalize() para worker entrypoints propios. No hay breaking changes. Ninguno de los tres cambia lo que puedes construir con Astro; los tres cambian cuánto tiempo pierdes cuando algo se rompe.

    Todo lo que cuento aquí sale de las notas oficiales de la release de Astro 7.3, del changelog de astro 7.3.0, del changelog de @astrojs/cloudflare y de la referencia de CLI de Astro.

    Vamos con el primero, que es el que más gente va a notar hoy mismo.


    --ignore-lock llega a astro preview: el arreglo que se nota en el CI

    astro preview levanta un servidor sobre tu build de producción. Es contra ese servidor contra el que corren tus tests E2E, porque probar contra astro dev es probar otra cosa: otro pipeline, otros assets, otro comportamiento.

    Desde Astro 7.2, ese comando escribe un lockfile en .astro/preview.json — el mismo mecanismo que astro dev usa en .astro/dev.json desde Astro 7.0. Un servidor de preview por proyecto y punto: si intentas levantar el segundo, no arranca.

    Astro 7.3 devuelve la escotilla:

    npx astro preview --port 4322 --ignore-lock
    

    El flag se salta la comprobación del lockfile y te deja arrancar tantos servidores de preview como quieras sobre el mismo proyecto, cada uno en su puerto. En Playwright, que es el caso de uso que el propio equipo de Astro menciona en las notas, se traduce en esto:

    // playwright.config.ts
    import { defineConfig } from '@playwright/test';
    
    export default defineConfig({
      webServer: [
        {
          command: 'npx astro preview --port 4321 --ignore-lock',
          url: 'http://localhost:4321',
          reuseExistingServer: !process.env.CI,
        },
        {
          command: 'npx astro preview --port 4322 --ignore-lock',
          url: 'http://localhost:4322',
          reuseExistingServer: !process.env.CI,
        },
      ],
    });
    

    Hay un detalle que conviene leer dos veces. Las notas oficiales avisan de que estas instancias corren de forma independiente, así que están pensadas para servidores rápidos y de usar y tirar, no para los que gestionas con astro preview stop o astro preview status. Traducido: si los arrancas a mano, los matas a mano. Dentro de Playwright da igual, porque el teardown del webServer se encarga.

    Y un aviso que no está en el anuncio de la release pero sí en la referencia del CLI: --ignore-lock no se puede combinar con --background ni con --force, porque los dos dependen del lockfile. Si los juntas, Astro lanza un error.

    Lo que convierte eso en un problema real: Astro activa el modo background por su cuenta cuando detecta que quien ejecuta el comando es un agente de IA. Traducido: si lanzas la suite desde dentro de una sesión de Claude Code o de Cursor, tu --ignore-lock puede petar sin que hayas escrito --background en ninguna parte.

    La salida está documentada y es una variable de entorno:

    ASTRO_PREVIEW_BACKGROUND=0 npx astro preview --port 4322 --ignore-lock
    

    Si lanzas Playwright desde tu terminal, esto no te afecta. Si lo lanza un agente por ti, ponla en el webServer y te ahorras el segundo día de depuración.

    Y hay un segundo escenario, menos obvio y más frecuente de lo que parece: no necesitas dos suites en paralelo para chocar con el candado. Basta con que algo ya lo tenga cogido. Un preview huérfano de la ejecución anterior. O tu agente de IA, que dejó uno levantado en segundo plano mientras trabajaba.

    Esto último no es hipotético, y aquí es donde la release se pone interesante.


    El candado no lo pusieron por ti

    Astro 7 introdujo el lockfile en astro dev con un motivo explícito, y lo dicen ellos con todas las letras en su blog: para que los agentes de IA no levantaran servidores de desarrollo duplicados del mismo proyecto sin darse cuenta. Un problema que hace tres años no existía.

    La secuencia completa es esta:

    Versión Qué pasó
    Astro 7.0 Llega el lockfile a astro dev para frenar servidores duplicados de agentes de IA
    Astro 7.1 Se añade --ignore-lock a astro dev para quien sí quiere varios a propósito
    Astro 7.2 El lockfile se extiende a astro preview, pero sin escotilla
    Astro 7.3 --ignore-lock llega también a astro preview

    Si te interesa el contexto de dónde salió todo esto, lo conté cuando salió la major en el repaso de novedades de Astro v7.

    Aquí está la lección, y va mucho más allá de Astro.

    Tus herramientas están empezando a poner defaults pensados para un agente, no para ti. El lockfile es una decisión sensata cuando quien ejecuta el comando es un modelo que no recuerda si ya levantó el servidor hace diez minutos. Es una decisión molesta cuando quien lo ejecuta eres tú, con un playwright.config.ts delante y muy claro lo que quieres.

    Astro lo ha resuelto bien: default seguro para el agente, flag explícito para el humano. Pero el patrón se va a repetir en todo tu stack, y la próxima vez a lo mejor no te dan el flag el mismo trimestre.

    Por eso insisto tanto en esto cuando trabajo con agentes en el curso de Construye con IA: tienes que saber qué procesos deja vivos tu agente. No porque vaya a romper nada grave, sino porque el día que tu CI falle por un lockfile vas a perder dos horas buscando el bug en tu código.

    Y ya que estamos en testing: el E2E es la capa cara. Casi todo lo que quieres verificar debería estar cubierto más abajo, donde una prueba cuesta milisegundos — lo desarrollé en pruebas unitarias ultrarrápidas con Vitest.


    El logger de runtime llega a los image services y a los cache providers

    Segundo cambio. Menos vistoso, y sin embargo es el que arregla un problema de higiene real.

    Si mantienes un image service custom —el típico wrapper sobre Cloudinary, imgproxy o tu propio CDN— hasta ahora tu única forma de avisar de algo era console.warn(). Con la consecuencia obvia: ese warning se escupía siempre. Ignoraba el nivel de log del proyecto, ignoraba --silent y ensuciaba la salida del build igual en local que en CI.

    En Astro 7.3, los image services reciben el logger de Astro como argumento adicional en transform():

    import type { LocalImageService } from 'astro';
    
    const service: LocalImageService = {
      // ...
      async transform(inputBuffer, transform, imageConfig, logger) {
        logger.warn(`No se pudo optimizar "${transform.src}". Se devuelve sin tocar.`);
        return { data: inputBuffer, format: 'png' };
      },
    };
    

    Y los cache providers lo reciben dentro del contexto que se pasa a onRequest():

    import type { CacheProvider } from 'astro';
    
    const provider: CacheProvider = {
      name: 'my-cache',
      async onRequest({ request, url, logger }, next) {
        logger.warn(`Caché omitida en ${url.pathname}: la respuesta define una cookie.`);
        return next();
      },
      // ...
    };
    

    El servicio Sharp integrado y el provider memoryCache() ya están migrados. Sharp lo usa para avisar de formatos de origen raros o no soportados; memoryCache(), para avisar de respuestas que se salta y de fallos en la revalidación en segundo plano.

    La ganancia no es que ahora "haya logs". Es que tus warnings viajan por el mismo canal que los de Astro y respetan la configuración del proyecto. Si mantienes una integración propia, es un cambio de dos líneas.

    Y sí, esto entra de lleno en la conversación de rendimiento: el image service es una de las piezas que decide el peso real de tus páginas, igual que las Server Islands que analicé en sitios web ultrarrápidos con Astro.


    finalize() en @astrojs/cloudflare: el bug silencioso de las cookies

    Tercer cambio, el más de nicho y el más peligroso de los tres si te toca.

    Va para quien despliega en Cloudflare con un worker entrypoint propio en lugar del que genera el adapter. Ese pipeline manual funciona, pero se salta un paso: aplicar las cookies y los defaults de caché del CDN de Cloudflare a la respuesta que devuelve astro/fetch.

    Un bug de esos que no rompe el build. Simplemente un día descubres que las cookies de sesión no llegan.

    @astrojs/cloudflare 14.3.0, publicada el 3 de septiembre de 2026 —el mismo día que Astro 7.3—, añade finalize() para cerrar ese hueco. Recibe el FetchState y la respuesta del pipeline, y devuelve la respuesta ya con las cookies y la caché aplicadas:

    // src/worker.ts
    import { astro, FetchState } from 'astro/fetch';
    import { cf, finalize } from '@astrojs/cloudflare/fetch';
    
    export default {
      async fetch(request: Request, env: Env, context: ExecutionContext) {
        const state = new FetchState(request);
        const asset = await cf(state, env, context);
        if (asset) return asset;
    
        return finalize(state, await astro(state));
      },
    };
    

    Si usas Hono, no tienes que hacer nada: el middleware @astrojs/cloudflare/hono aplica esas cabeceras por su cuenta.

    El resto de la release te ahorra tiempo. Esta te ahorra un incidente.


    ¿Te toca actualizar a Astro 7.3?

    No hay breaking changes, así que la pregunta no es si puedes, es si ganas algo.

    Tu situación Qué hacer Por qué
    Tienes E2E con Playwright sobre astro preview Actualiza hoy Es la diferencia entre una suite que arranca y una que muere en el webServer
    Trabajas a diario con un agente de IA en el proyecto Actualiza hoy Dejas de pelearte con él por el mismo lockfile
    Mantienes un image service o cache provider custom Actualiza y cambia dos líneas Tus warnings pasan a respetar el nivel de log y --silent
    Despliegas en Cloudflare con worker entrypoint propio Sube @astrojs/cloudflare a 14.3.0 finalize() te quita el bug silencioso de las cookies
    Sitio estático, sin E2E, sin adapter Actualiza sin prisa No hay riesgo, pero tampoco premio

    Si vienes de la rama 6.x, el salto que de verdad cambió cómo se construye con Astro no es este: fue el de Server Islands y Actions en 6.2. Astro 7.3 es mantenimiento fino sobre esa base.


    Lo que yo haría esta semana

    Abre tu playwright.config.ts y mira si el command del webServer llama a astro preview. Si es que sí, añade --ignore-lock y actualiza. Son treinta segundos y te ahorras el día en que el CI falle por un lockfile que tú no pusiste.

    El resto puede esperar al próximo sprint.

    Pero quédate con la idea de fondo, porque vale más que los tres cambios juntos: tu tooling ha empezado a asumir que quien escribe los comandos es un agente. Los defaults se están moviendo hacia ahí. Cuando algo se rompa de forma rara en tu pipeline, esa es la primera hipótesis que deberías poner sobre la mesa, y ya no la última.

    De esto discutimos bastante en Dominicode Labs, porque casi todos los que estamos metiendo agentes en el flujo diario nos hemos comido alguna versión de este mismo problema.


    Preguntas frecuentes

    ¿Qué hace exactamente –ignore-lock en astro preview?

    Se salta la comprobación del lockfile que Astro 7.2 añadió a astro preview, de modo que puedes tener varios servidores de preview del mismo proyecto corriendo a la vez en puertos distintos. El flag ya existía en astro dev desde Astro 7.1; la 7.3 lo lleva también a preview.

    ¿Por qué astro preview –ignore-lock me da error?

    Porque --ignore-lock no se puede combinar con --background ni con --force: las dos opciones dependen del lockfile, así que Astro lanza un error. Y cuando Astro detecta que el comando lo ejecuta un agente de IA, activa el modo background automáticamente, aunque tú no hayas pasado --background. Si te ocurre, desactiva ese automatismo con la variable de entorno ASTRO_PREVIEW_BACKGROUND=0 delante del comando.

    ¿Por qué existe ese lockfile si nadie lo pidió?

    Porque Astro 7 lo introdujo para que los agentes de IA no levantaran servidores duplicados del mismo proyecto sin darse cuenta. Es un default pensado para un ejecutor que no recuerda si ya arrancó el servidor hace diez minutos, y por eso convive mal con flujos donde tú quieres varios servidores a propósito.

    ¿Los servidores lanzados con –ignore-lock se gestionan con astro preview stop?

    No. Las notas oficiales avisan de que esas instancias corren de forma independiente y están pensadas para servidores rápidos y de usar y tirar, no para los que administras con astro preview stop o astro preview status. Si los arrancas a mano, los cierras a mano; dentro de Playwright se encarga el teardown del webServer.

    ¿Tengo que tocar mi image service custom para aprovechar el logger?

    Solo si quieres. El cambio es aditivo: el logger llega como argumento adicional en transform() y dentro del contexto de onRequest() en los cache providers, así que tu código actual sigue funcionando. Cambiar console.warn() por logger.warn() es lo que hace que tus avisos respeten el nivel de log configurado y el flag --silent.

    ¿Necesito llamar a finalize() si uso Hono en Cloudflare?

    No. El middleware @astrojs/cloudflare/hono aplica esas cabeceras automáticamente. finalize() está pensado para quien monta un worker entrypoint propio sobre astro/fetch y necesita aplicar a mano las cookies y los defaults de caché del CDN de Cloudflare.

    ¿En qué versión de @astrojs/cloudflare está finalize()?

    En @astrojs/cloudflare 14.3.0, publicada el 3 de septiembre de 2026 junto a Astro 7.3. El adapter se versiona aparte de astro: subir astro a 7.3 no actualiza el adapter, tienes que subir los dos paquetes.

    ¿Hay breaking changes al actualizar a Astro 7.3?

    No. Es una release menor de mantenimiento sobre la 7.2: un flag nuevo, un logger que se propaga a APIs de extensión y un helper añadido en @astrojs/cloudflare 14.3. La actualización del adapter de Cloudflare va aparte de la de astro, así que revisa que subes las dos si estás en ese escenario.


    Si prefieres ver este tipo de análisis en vídeo, con el proyecto delante, lo publico en el canal de YouTube de Dominicode.

    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Starlight 0.42: menos JavaScript, menú móvil roto en silencio

    Starlight 0.42: menos JavaScript, menú móvil roto en silencio

    El viernes actualicé la documentación de un proyecto interno a Starlight 0.42. npx @astrojs/upgrade, build en verde, Lighthouse un punto mejor. Cerré el portátil.

    El lunes un compañero me pasa una captura desde el móvil. El menú abría perfecto. Pero el botón se quedaba gris. Nuestro color de marca al abrir el menú había desaparecido.

    Nada había fallado. Ese es el problema. El CSS no lanza errores: cuando un selector deja de coincidir con algo, se calla y sigue. El build no te avisa, los tests no lo ven y tú te enteras cuando alguien abre el sitio en un teléfono.

    El anuncio oficial de la release vende una paradoja simpática —menos JavaScript y más JavaScript a la vez— y para los detalles te remite al CHANGELOG. Este post es el CHANGELOG explicado, con el CSS concreto que tienes que cambiar.

    El titular es "menos JavaScript". La letra pequeña es que si tocaste el menú móvil con CSS o JS propio, la 0.42 te lo rompe sin decir nada.


    La paradoja de Starlight 0.42: "un 100 % más de JavaScript"

    El chiste es del propio anuncio y tiene truco. Hay dos JavaScript distintos aquí y el post oficial los mezcla a propósito.

    Uno es el JavaScript que va dentro del paquete de npm. Ese sube: Starlight ha dejado de publicar TypeScript y ahora distribuye JavaScript compilado.

    El otro es el JavaScript que llega al navegador de quien lee tu documentación. Ese baja: el menú móvil ya no necesita JS para funcionar.

    Build-time contra runtime. Son cosas distintas y confundirlas es el error clásico al leer notas de release. Con la 0.42 en la mano, un sitio Starlight medio sigue enviando entre 3 y 13 veces menos JavaScript al usuario final que herramientas comparables: MkDocs, Sphinx, VitePress, Nextra, GitBook o Docusaurus.

    Es la misma lógica que ya movía a Astro con las server islands: decidir con precisión qué se ejecuta en el servidor y qué viaja al cliente, en vez de mandarlo todo y confiar. Astro lleva varias releases insistiendo en lo mismo, desde que server islands y actions se estabilizaron en la 6.2.


    Por qué Starlight publicaba TypeScript y por qué ha parado

    Hay una rareza de los proyectos Astro que mucha gente no conoce: puedes publicar archivos .ts directamente en npm y funcionan cuando alguien los instala. Sin build step. Genial para prototipar rápido, y así se venía publicando Starlight desde el principio.

    El coste aparecía en tu proyecto, no en el suyo.

    Si haces typecheck con tsc, TypeScript revisa cualquier .ts que encuentre importado, incluso dentro de node_modules. Así que acababas comprobando el código fuente de Starlight. Y no con la configuración del paquete, sino con la tuya. En algunos casos el rendimiento de tipos en el editor también se resentía. En una base de código del tamaño de Starlight, esos problemas se acumulan.

    La 0.42 compila sus fuentes y distribuye JavaScript más archivos de declaración (.d.ts). El resultado esperable es un typecheck más rápido en tu máquina — y más aún cuando aterrice el compilador de TypeScript escrito en Go.

    Detalle que conviene tener claro: un .d.ts describe tipos en tiempo de compilación y desaparece en tiempo de ejecución. No valida nada.

    La validación de verdad ya la estás usando aunque no te hayas fijado: el frontmatter de tus páginas lo comprueba Starlight con esquemas de Zod durante el build. Y si tu sitio además tiene formularios o endpoints, ahí hace falta el mismo tipo de esquema pero ejecutándose en runtime. Tipos y validación resuelven problemas distintos, aunque la gente los meta en el mismo saco.


    La Popover API: por qué el menú móvil deja de necesitar tu JavaScript

    Aquí está el cambio de fondo.

    Antes, el menú móvil era una máquina de estados escrita a mano: un custom element <starlight-menu-button> que escuchaba clics, cambiaba aria-expanded en el botón y ponía un atributo en el <body>. Si el JavaScript no llegaba a ejecutarse, no había menú.

    Y hay más razones de las que la gente cree para que el JavaScript no se ejecute. La red se cae a medias. Otro script peta antes y se lleva por delante el resto del bundle. Una extensión del navegador se mete por medio. Alguien lo tiene desactivado. En un sitio de documentación —que muchas veces es la primera vez que alguien te ve— eso es una puerta cerrada.

    La 0.42 delega ese estado en la Popover API del navegador. El menú abre aunque tu JavaScript nunca llegue.

    Menos código propio, más primitiva nativa. Es la dirección correcta.

    Pero ojo con la consecuencia: si el estado ya no vive en un atributo del botón, tu CSS no tiene a qué agarrarse.


    Los 3 breaking changes de Starlight 0.42, en una tabla

    Starlight 0.42 rompe tres cosas y solo tres. Esta es la traducción directa de código viejo a código nuevo:

    Qué desaparece Reemplazo en 0.42 A quién afecta
    <starlight-menu-button> y aria-expanded .sl-menu-button y .sl-menu-button:has(~ :popover-open) Estilos, temas o component overrides que apuntaban al botón del menú móvil
    body[data-mobile-menu-expanded] body:has(sl-sidebar-pane:popover-open) CSS o JS propio que reaccionaba a la apertura del menú
    Opción tagline en astro.config Sin reemplazo: se borra Configs que la declararon (nunca hizo nada)

    Si ninguna de las tres filas aparece en tu código, la actualización es transparente. Si aparece alguna, las tres secciones siguientes son tuyas.


    Breaking change 1: el botón del menú móvil

    El botón ya no va envuelto en el custom element <starlight-menu-button> y ya no usa aria-expanded. Ahora apuntas al botón con la clase .sl-menu-button y lees el estado abierto con la pseudo-clase :popover-open.

    Así estaba tu CSS antes:

    /* Antes: Starlight 0.41 y anteriores */
    starlight-menu-button button {
      border-radius: 999px;
      background: var(--sl-color-gray-6);
    }
    
    starlight-menu-button[aria-expanded="true"] button {
      background: var(--dc-brand);
      color: var(--sl-color-white);
    }
    

    Y así queda en la 0.42:

    /* Después: Starlight 0.42 */
    .sl-menu-button {
      border-radius: 999px;
      background: var(--sl-color-gray-6);
    }
    
    /* El estado abierto lo expone el navegador en el panel, no en el botón.
       Seleccionas el botón que tiene un popover abierto como hermano. */
    .sl-menu-button:has(~ :popover-open) {
      background: var(--dc-brand);
      color: var(--sl-color-white);
    }
    

    Fíjate en lo que ha cambiado de verdad. No es un nombre de clase: es de quién es el estado.

    Antes el estado estaba en el botón, porque lo escribía JavaScript. Ahora está en el panel, porque lo gestiona el navegador. Por eso el selector nuevo tiene que ser relacional: :has() con ~ :popover-open significa "este botón, cuando un hermano posterior suyo está abierto".


    Breaking change 2: adiós a data-mobile-menu-expanded

    El atributo data-mobile-menu-expanded que Starlight añadía al <body> mientras el menú estaba abierto ya no existe. Si lo usabas para ocultar una barra flotante, bloquear el scroll o apagar una animación, ese bloque de CSS ha dejado de aplicarse.

    /* Antes */
    body[data-mobile-menu-expanded] .dc-cta-flotante {
      display: none;
    }
    
    /* Después */
    body:has(sl-sidebar-pane:popover-open) .dc-cta-flotante {
      display: none;
    }
    

    Si además tenías JavaScript propio reaccionando al menú, el cambio te ahorra código. Antes tocaba vigilar un atributo:

    // Antes: espiar el atributo que ponía Starlight
    const boton = document.querySelector('starlight-menu-button button');
    
    new MutationObserver(() => {
      const abierto = boton.getAttribute('aria-expanded') === 'true';
      document.body.classList.toggle('menu-abierto', abierto);
    }).observe(boton, { attributeFilter: ['aria-expanded'] });
    

    Ahora el navegador te lo cuenta él solo con un evento nativo:

    // Después: el panel es el popover y emite un evento toggle
    const panel = document.querySelector('sl-sidebar-pane[popover]');
    
    panel?.addEventListener('toggle', (event) => {
      const abierto = event.newState === 'open';
      document.body.classList.toggle('menu-abierto', abierto);
    });
    

    Un MutationObserver menos en tu sitio. Esa es la parte buena de apoyarse en primitivas del navegador: el código que borras no puede fallar.


    Breaking change 3: la opción tagline ya no existe

    Se elimina de la configuración. Nunca se llegó a usar para nada, así que no hay reemplazo: la borras de tu astro.config y listo. Si no la quitas, la validación de config te lo dirá.


    Requisitos mínimos y navegadores que se caen

    Starlight 0.42 exige Astro v7.2.10 o superior. Si usas @astrojs/markdown-satteri, necesitas 0.4.0 o superior. Si sigues con @astrojs/markdown-remark, 7.3.0 o superior.

    Si tu sitio todavía está en Astro v6, el salto grande no es este release, es el anterior: repasa primero las novedades de Astro v7 y hazlo en un PR aparte. Actualizar dos majors en el mismo commit es la forma más rápida de perder la tarde.

    Y hay una lista de navegadores que dejan de tener soporte oficial:

    Navegador Versión mínima soportada
    Chromium 116 (agosto de 2023)
    Safari 17.0 (septiembre de 2023)
    Firefox 125 (abril de 2024)

    No es un capricho, pero tampoco es el mínimo exacto de la API. Firefox 125 y Safari 17.0 son justo las versiones donde aterrizó la Popover API. En Chromium llegó antes, en la 114, así que ahí Starlight se ha guardado dos versiones de margen. Y en iPhone no hay sorpresa: el Safari de iOS la soporta desde la misma 17.0 que el de escritorio.

    El precio de apoyarse en el navegador es aceptar su calendario. Mira tus analíticas antes de decidir: en un sitio de documentación técnica, ese tráfico suele redondear a cero.


    Lo que mejora sin que hagas nada

    Dos cosas llegan gratis con la actualización.

    Rendimiento. La última versión de Sätteri —el motor de Markdown y MDX de Astro escrito en Rust, que llegó en Astro 6.4 y es el motor por defecto desde Astro 7— les ha permitido optimizar componentes y plugins de Markdown, y reducir el número de dependencias de Starlight. El procesado de datos del sidebar es ahora hasta 1.400 veces más rápido, y eso se nota de verdad en sitios con sidebars grandes o muy anidados.

    Ojo con un detalle que no es opcional. Sätteri no ejecuta plugins de remark ni de rehype: tiene su propio sistema de plugins mdast y hast, y no hay fallback automático.

    Y aquí no eliges tú. Como es el motor por defecto de Astro 7, y la 0.42 exige Astro v7.2.10 o superior, la actualización te lo puede cambiar sola. Si tu pipeline depende de remark o rehype, tienes que quedarte explícitamente en @astrojs/markdown-remark 7.3.0 o superior. Compruébalo antes de lanzar el upgrade, no después.

    Accesibilidad. El menú móvil atrapa el foco mientras está abierto, para que no puedas tabular hacia la página que queda escondida debajo. Detrás está el criterio de éxito WCAG 2.4.11, «Focus Not Obscured (Minimum)»: el elemento con el foco no puede quedar tapado por lo que hay encima. Se agradece en viewports pequeños o con mucho zoom. Llegó en la 0.41.3, así que si vienes de la última 0.41.x ya lo tienes. Si esto lo habías parcheado tú a mano, bórralo: ahora hay dos implementaciones peleándose por el foco.


    Cómo actualizar a Starlight 0.42 paso a paso

    1. Comprueba que estás en Astro v7. Starlight 0.42 exige Astro v7.2.10 o superior. Si vienes de Astro v6, haz ese salto antes y en un PR aparte.

    2. Busca lo que se va a romper. Cuatro grep antes de tocar nada:

      grep -rn "starlight-menu-button" src/
      grep -rn "data-mobile-menu-expanded" src/
      grep -rn "aria-expanded" src/styles/
      grep -rn "tagline" astro.config.*
      

      Cada resultado es una línea que hay que migrar. Si no aparece nada, actualiza tranquilo.

    3. Actualiza. Un solo comando sube Starlight, Astro y el resto de integraciones a la vez:

      npx @astrojs/upgrade
      
    4. Migra el CSS y el JS con la tabla de equivalencias de más arriba: .sl-menu-button, .sl-menu-button:has(~ :popover-open) y body:has(sl-sidebar-pane:popover-open).

    5. Abre el sitio en un móvil de verdad y toca el botón del menú. No en el simulador de Chrome: en un teléfono. Es el único sitio donde estos tres breaking changes se manifiestan.

    Este tipo de migración quirúrgica —buscar patrones muertos, cambiarlos y verificar— es exactamente lo que un agente hace bien si le das el CHANGELOG y los selectores concretos. Es el flujo que enseño en Construye con IA: contexto preciso primero, ejecución después.


    La conclusión que te llevas

    Un release que quita JavaScript casi siempre mueve el estado a otro sitio. Y el CSS que apuntaba al estado viejo no se queja: se apaga. Es el mismo patrón que en los breaking changes de pnpm 12: la nota de release vende el titular y el trabajo real está tres párrafos más abajo.

    Si mantienes un sitio con Starlight, haz hoy los cuatro grep de arriba antes de actualizar. Tardas menos de lo que has tardado en leer este post, y te ahorras la captura de un compañero el lunes por la mañana.

    En Dominicode Labs trabajamos este tipo de migraciones sobre proyectos reales, con el diff delante en vez de con el anuncio de marketing. Y el anuncio original, por si quieres la versión oficial, está en el blog de Astro.


    Preguntas frecuentes

    ¿Cómo actualizo a Starlight 0.42?

    Ejecuta npx @astrojs/upgrade, que sube Starlight, Astro y el resto de integraciones a la vez. Antes de lanzarlo, busca en tu proyecto starlight-menu-button, data-mobile-menu-expanded, aria-expanded en tus estilos y tagline en astro.config: cada coincidencia es una línea que hay que migrar. Necesitas Astro v7.2.10 o superior. Después, abre el sitio en un móvil real y comprueba el botón del menú.

    ¿Starlight 0.42 envía más o menos JavaScript al navegador?

    Menos. El "100 % más de JavaScript" del anuncio se refiere al paquete de npm, que ahora se distribuye compilado a JavaScript en lugar de TypeScript. Lo que llega al navegador de quien lee tu documentación baja, porque el menú móvil se apoya en la Popover API nativa en vez de en código propio. Un sitio Starlight medio sigue enviando entre 3 y 13 veces menos JavaScript al usuario final que MkDocs, Sphinx, VitePress, Nextra, GitBook o Docusaurus.

    ¿Por qué ha dejado de aplicarse mi CSS del menú móvil tras actualizar?

    Porque el botón ya no va envuelto en el custom element <starlight-menu-button> y ya no usa el atributo aria-expanded. Cualquier selector construido sobre esos dos elementos deja de coincidir con nada y el navegador lo ignora en silencio. La migración es apuntar al botón con .sl-menu-button y leer el estado abierto con .sl-menu-button:has(~ :popover-open).

    ¿Por qué el selector nuevo usa :has() en lugar de una clase en el botón?

    Porque el estado ha cambiado de dueño. Antes lo escribía JavaScript en el botón; ahora lo gestiona el navegador en el panel del menú, que es el elemento popover. Para estilar el botón según ese estado necesitas un selector relacional: :has(~ :popover-open) significa "este botón, cuando un hermano posterior suyo está abierto". Para el <body>, el equivalente del antiguo data-mobile-menu-expanded es body:has(sl-sidebar-pane:popover-open).

    ¿Qué versiones mínimas necesito para actualizar a Starlight 0.42?

    Astro v7.2.10 o superior. Si usas @astrojs/markdown-satteri, 0.4.0 o superior. Si usas @astrojs/markdown-remark, 7.3.0 o superior. El comando npx @astrojs/upgrade se encarga de subir Starlight, Astro y el resto de integraciones a la vez.

    ¿Debería preocuparme por los navegadores que pierden soporte?

    Depende de tus analíticas, pero casi nunca. Se cae el soporte oficial de Chromium anterior a la 116 (agosto de 2023), Safari anterior a 17.0 (septiembre de 2023) y Firefox anterior a 125. Son los mínimos que exige la Popover API. En documentación técnica ese tráfico suele ser residual; míralo antes de bloquear la actualización por si acaso.

    ¿Qué hago si tenía JavaScript propio escuchando la apertura del menú?

    Bórralo y escucha el evento nativo. El panel es el popover, así que un panel.addEventListener('toggle', ...) con event.newState === 'open' te da lo mismo que antes conseguías con un MutationObserver sobre aria-expanded, con la mitad de código y sin depender de detalles internos de Starlight.

    ¿Y la opción tagline de la configuración?

    Se ha eliminado y no tiene reemplazo, porque nunca se llegó a usar. Bórrala de tu astro.config al actualizar.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Astro v7: novedades clave y cómo crear tu landing desde cero

    Astro v7: novedades clave y cómo crear tu landing desde cero

    Un developer me escribió hace unas semanas. Tenía una landing page para un producto que estaba a punto de lanzar. La había montado con Next.js porque “era lo que conocía”. El tiempo de build era de 4 minutos. El bundle pesaba más de lo que debería. Y lo único que necesitaba era una página estática con una sección hero, tres features y un formulario de contacto.

    Next.js para eso es como usar un martillo neumático para clavar un cuadro.

    La respuesta que le di fue una sola palabra: Astro. Y ahora, con Astro v7, esa respuesta es más sólida que nunca.


    Qué es Astro, por si llevas tiempo mirando para otro lado

    Astro es un framework de generación de sitios estáticos que tiene una idea central brillante: envía cero JavaScript al cliente por defecto. Solo envía HTML y CSS. Si necesitas interactividad en algún componente concreto, la añades con lo que quieras: React, Vue, Svelte, Lit — Astro lo llama “islands”.

    Para landings, blogs, documentación y cualquier sitio orientado al contenido, no hay nada más rápido ni más sencillo de mantener.

    Astro v7 lleva esa idea más lejos que nunca. Y los números lo avalan.


    Las novedades reales de Astro v7

    Astro v7 es la séptima versión mayor del framework, lanzada en 2026, que introduce un compilador reescrito en Rust, Vite 8 con Rolldown y Route Caching estable como cambios principales. Es la versión con el mayor salto de rendimiento desde el lanzamiento del framework.

    El compilador se reescribió en Rust — y se nota

    La parte más importante de esta versión no es una nueva API. Es que el compilador de .astro pasó de estar escrito en Go a estar escrito en Rust.

    El resultado: builds entre un 15% y un 61% más rápidos en benchmarks reales. El sitio de documentación oficial de Astro pasó de tardar 114 segundos en construirse a 73. El propio astro.build bajó de 62 segundos a 24 (datos oficiales del blog de Astro).

    Eso es el tipo de mejora que no se consigue ajustando configuraciones. Es un cambio de arquitectura.

    El tradeoff: el compilador Rust es más estricto con HTML inválido. Antes, si dejabas una etiqueta sin cerrar, Astro la corregía silenciosamente. Ahora lanza un error. Lo cual, seamos honestos, es el comportamiento correcto.

    Vite 8 con Rolldown — el bundler en Rust también

    Astro v7 actualiza a Vite 8, que trae Rolldown: un bundler escrito en Rust que reemplaza tanto a esbuild como a Rollup con una sola herramienta unificada. En benchmarks, es 10-30 veces más rápido que Rollup.

    La compatibilidad con la API de plugins de Rollup y Vite se mantiene. Si tienes plugins existentes, seguirán funcionando.

    Nuevo procesador Markdown: Sätteri

    El pipeline de Markdown ha cambiado por completo. El procesador anterior basado en unified, remark y rehype ha sido reemplazado por Sätteri, un procesador escrito también en Rust.

    Sätteri incluye de serie: GitHub Flavored Markdown, tipografía inteligente, IDs de encabezados, directivas, matemáticas y frontmatter. Sin configuración adicional.

    Si tenías plugins personalizados de remark o rehype, puedes volver al pipeline anterior instalando @astrojs/markdown-remark y configurándolo explícitamente. No pierdes nada — solo dejas de tenerlo por defecto.

    Route Caching ahora es estable

    El sistema de caché de rutas, que estaba en experimental, ya es parte de la API estable. Puedes controlar el caché de cada respuesta con una API agnóstica a la plataforma:

    // En cualquier página .astro o endpoint
    Astro.cache.set({
      maxAge: 120,     // 2 minutos en caché de cliente/servidor
      swr: 60,         // 1 minuto de revalidación en background
      tags: ['products']
    });

    Y cuando necesitas invalidar:

    await cache.invalidate({ tags: ['products'] });

    Para Netlify, Vercel y Cloudflare hay CDN cache providers experimentales que traducen estas directivas a la capa edge de cada plataforma.

    Advanced Routing — control total del pipeline

    Astro v7 introduce un archivo src/fetch.ts que te da acceso completo al pipeline de solicitudes, antes de que Astro las procese. Compatible con Hono para middleware:

    // src/fetch.ts
    import { astro } from 'astro/fetch';
    
    

    export default { fetch(request: Request) { const url = new URL(request.url);

    // Intercepta rutas /api antes de que lleguen a Astro if (url.pathname.startsWith('/api')) { return fetch('https://mi-backend.com' + url.pathname, request); }

    return astro(request); } }

    Si ya tienes un src/fetch.ts propio en tu proyecto, Astro v7 lo detectará y te pedirá que lo renombres o que desactives esta feature.

    Modo para agentes IA

    Esto es interesante si construyes herramientas con IA o trabajas con Claude Code, Cursor u otros coding agents. Astro v7 detecta automáticamente cuando está corriendo dentro de un agente y activa dos comportamientos:

    1. Inicia el servidor de desarrollo en modo background con astro dev --background
    2. Cambia los logs a formato JSON estructurado para que el agente los pueda parsear
    # Arranque idempotente — no lanza otro servidor si ya hay uno corriendo
    astro dev --background
    
    

    # Estado del servidor astro dev status

    # Logs en JSON astro dev --json


    Astro v6 vs v7 — qué cambió exactamente

    Área Astro v6 Astro v7
    Compilador .astro Go Rust (15-61% más rápido)
    Bundler Vite 7 + Rollup Vite 8 + Rolldown (Rust)
    Procesador Markdown unified / remark / rehype Sätteri (Rust, GFM incluido)
    Route Caching Experimental Estable (Astro.cache.set)
    Routing avanzado No disponible src/fetch.ts estable
    Modo agente IA No disponible astro dev --background + logs JSON
    HTML inválido Corregido silenciosamente Error de compilación (más estricto)
    @astrojs/db Disponible Eliminado → migrar a node:sqlite

    Cómo crear tu landing con Astro v7 — paso a paso

    Paso 1 — Instalación

    npm create astro@latest mi-landing

    El wizard te preguntará si quieres una plantilla vacía, con blog, o con un starter. Para una landing, elige “Empty” o “A basic, minimal starter”.

    cd mi-landing
    npm run dev

    Tu servidor de desarrollo estará en http://localhost:4321.

    Paso 2 — Estructura del proyecto

    mi-landing/
    ├── public/
    │   └── favicon.svg
    ├── src/
    │   ├── components/
    │   │   ├── Header.astro
    │   │   ├── Hero.astro
    │   │   ├── Features.astro
    │   │   └── Footer.astro
    │   ├── layouts/
    │   │   └── BaseLayout.astro
    │   └── pages/
    │       └── index.astro
    ├── astro.config.mjs
    └── package.json

    Paso 3 — El layout base

    ---
    // src/layouts/BaseLayout.astro
    interface Props {
      title: string;
      description: string;
    }
    
    

    const { title, description } = Astro.props;


    <!doctype html> <html lang="es"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="description" content={description} /> <title>{title}</title> </head> <body> <slot /> </body> </html>

    Paso 4 — Los componentes de la landing

    ---
    // src/components/Hero.astro
    interface Props {
      headline: string;
      subheadline: string;
      ctaText: string;
      ctaHref: string;
    }
    
    

    const { headline, subheadline, ctaText, ctaHref } = Astro.props;


    <section class="hero"> <h1>{headline}</h1> <p>{subheadline}</p> <a href={ctaHref} class="cta-btn">{ctaText}</a> </section>

    <style> .hero { display: flex; flex-direction: column; align-items: center; padding: 4rem 1rem; text-align: center; gap: 1.5rem; }

    h1 { font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; line-height: 1.1; }

    .cta-btn { display: inline-block; padding: 0.9rem 2rem; background: #7c3aed; color: white; text-decoration: none; border-radius: 0.5rem; font-weight: 600; transition: opacity 0.2s; }

    .cta-btn:hover { opacity: 0.85; } </style>

    ---
    // src/components/Features.astro
    const features = [
      {
        icon: "⚡",
        title: "Velocidad real",
        description: "HTML puro en el cliente. Sin JavaScript innecesario."
      },
      {
        icon: "🧩",
        title: "Componentes modulares",
        description: "Divide la UI en piezas reutilizables con props tipadas."
      },
      {
        icon: "🚀",
        title: "Deploy en segundos",
        description: "Estático por defecto. Netlify, Vercel o Cloudflare Pages."
      }
    ];
    

    <section class="features"> <h2>Por qué esto funciona</h2> <ul class="features-grid"> {features.map((feature) => ( <li> <span class="icon">{feature.icon}</span> <h3>{feature.title}</h3> <p>{feature.description}</p> </li> ))} </ul> </section>

    <style> .features { padding: 4rem 1rem; max-width: 900px; margin: 0 auto; }

    h2 { text-align: center; font-size: 2rem; margin-bottom: 2.5rem; }

    .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 2rem; list-style: none; padding: 0; }

    .icon { font-size: 2rem; display: block; margin-bottom: 0.75rem; }

    h3 { font-size: 1.1rem; margin-bottom: 0.5rem; } </style>

    Paso 5 — La página principal que lo une todo

    ---
    // src/pages/index.astro
    import BaseLayout from '../layouts/BaseLayout.astro';
    import Hero from '../components/Hero.astro';
    import Features from '../components/Features.astro';
    

    <BaseLayout title="Mi Producto — La forma más rápida de hacer X" description="Descripción de 160 caracteres para el SEO." > <Hero headline="Resuelve X sin Y" subheadline="La frase que convierte la curiosidad en intención de compra." ctaText="Empieza gratis" ctaHref="#registro" /> <Features /> </BaseLayout>

    Paso 6 — Build y deploy

    # Build de producción
    npm run build
    
    

    # Preview local del build npm run preview

    El output es estático por defecto: la carpeta dist/ contiene HTML, CSS y los assets optimizados. Sube esa carpeta a Netlify, Vercel o Cloudflare Pages y estás listo.


    Los breaking changes que tienes que revisar si migras desde v6

    Si ya usas Astro y estás actualizando, el comando oficial es:

    npx @astrojs/upgrade

    Pero antes de ejecutarlo, ten en cuenta estos cuatro puntos:

    1. Etiquetas HTML sin cerrar ahora son errores. El compilador Rust no las corrige. Revisa tus componentes .astro buscando

    ,

  • o cualquier etiqueta no-void sin su cierre correspondiente.

    2. @astrojs/db ha sido eliminado. Si lo usabas, migra a node:sqlite (disponible desde Node.js 22.5.0), Drizzle ORM, Turso o cualquier alternativa SQL moderna.

    3. Los eventos de astro:transitions cambiaron. TRANSITION_BEFORE_PREPARATION y similares desaparecen. Sus equivalentes son strings directos como 'astro:after-swap'.

    4. Si tenías features en experimental, sácalas de ahí. queuedRendering, advancedRouting, cache y logger ya son estables. Muévelos al nivel raíz de astro.config.mjs.


    Por qué Astro v7 importa ahora mismo

    Astro es la respuesta correcta para landings y sites de documentación. No porque React sea malo, sino porque la herramienta correcta para contenido estático no es un SPA. Si estás construyendo productos con IA y quieres entender cómo encaja el frontend en ese stack, el post sobre el stack IA agéntica en 2026 te da el mapa completo de herramientas.

    El patrón que más se repite en los proyectos con IA que veo últimamente: alguien genera una landing con un agente y lo hace con el stack que “siempre ha usado”. El resultado: un bundle de React para servir contenido estático.

    Astro es la respuesta correcta para ese caso de uso. No porque React sea malo, sino porque la herramienta correcta para una landing o un site de documentación no es un SPA.

    El hecho de que Astro v7 ahora detecte agentes IA automáticamente no es un detalle menor — es una señal de hacia dónde va el ecosistema. Si usas Claude Code o Cursor para generar código, el post sobre cómo funciona el agentic loop explica el mecanismo detrás de esa integración.

    En el curso de Construye con IA trabajamos exactamente este tipo de decisiones: cuándo elegir Astro, cuándo Next.js tiene sentido, y cómo pasar de una idea a un producto sin arrastrar deuda técnica desde el primer día.

    Con el enfoque de Spec-Driven Development, diseñar la arquitectura de este tipo de landing antes de escribir la primera línea de código es lo que separa una landing que escala de una que se convierte en un problema de mantenimiento en seis meses.


    FAQ

    ¿Astro v7 es compatible con React, Vue o Svelte?

    Sí. Astro sigue siendo agnóstico al framework de UI. Puedes usar componentes de React, Vue, Svelte, Solid o cualquier otro framework compatible mediante el sistema de integraciones. Lo que cambia es que Astro no envía el runtime de esos frameworks al cliente a menos que marques explícitamente un componente con una directiva client:*.

    ¿Necesito migrar a Sätteri si tengo plugins de remark personalizados?

    No es obligatorio. Puedes instalar @astrojs/markdown-remark y configurar markdown: { processor: unified() } en tu astro.config.mjs para mantener el pipeline anterior. Sätteri es el nuevo default, pero el viejo pipeline sigue disponible.

    ¿Puedo usar Astro v7 para sitios con contenido dinámico, no solo estático?

    Sí. Astro soporta SSR (Server-Side Rendering) con adaptadores para Node.js, Netlify, Vercel y Cloudflare Workers. Con el nuevo Advanced Routing y src/fetch.ts tienes control total sobre el pipeline de solicitudes. Para contenido que cambia con frecuencia, el nuevo sistema de Route Caching con invalidación por tags es especialmente útil.

    ¿Cuánto cuesta migrar un proyecto de Astro v5 o v6 a v7?

    Depende del proyecto, pero el comando npx @astrojs/upgrade automatiza la mayor parte. Los cambios manuales más comunes son: cerrar etiquetas HTML que el compilador anterior perdonaba, eliminar @astrojs/db si lo usabas, y sacar las features que estaban en experimental al nivel raíz de la configuración. En un proyecto mediano, una tarde es suficiente.

    ¿Astro v7 es una buena opción para documentación técnica?

    Es probablemente la mejor opción disponible. El procesador Sätteri maneja GFM, directivas y matemáticas de serie. El sistema de content collections te permite estructurar MDX como si fuera una base de datos. Y los builds son ahora significativamente más rápidos, lo que importa cuando tienes cientos de páginas de documentación. No en vano, el propio sitio de documentación de Astro corre sobre Astro.


    Si quieres ver cómo integramos herramientas como Astro en un flujo de trabajo completo con IA — desde el spec hasta el deploy — en Dominicode Labs tenemos proyectos activos donde exploramos exactamente ese proceso.

    Y si prefieres empezar con vídeo, en el canal de YouTube de Dominicode hay contenido regular sobre desarrollo con IA, Angular, TypeScript y herramientas de producción.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Mejoras en Astro 6.2: Server Islands y Astro Actions

    Lo nuevo de Astro 6.2 y porque lo tienes que probar

    Tiempo estimado de lectura: 4 min

    • Rendimiento y entrega de HTML: Server Islands y mejoras que reducen el TTFB.
    • Ergonomía y seguridad: Astro Actions introduce RPC tipado con validación integrada.
    • Contenido externo en build: Content Layer trata APIs, CMS y bases como ciudadanos de primera clase.
    • Developer experience: arranques y HMR más rápidos en proyectos grandes o monorepos.

    Resumen y análisis técnico de las mejoras introducidas en Astro 6.2, con ejemplos prácticos y recomendaciones para equipos que priorizan rendimiento, tipado y manejo de contenido externo.

    Resumen rápido (lectores con prisa)

    Qué es: Actualización de Astro que mejora renderizado diferido, añade RPC tipado para mutaciones y consolida una capa de contenido para fuentes externas.

    Cuándo usarlo: Para sitios estáticos con zonas personalizadas, e-commerce y documentación donde SEO y Core Web Vitals importan.

    Por qué importa: Reduce JavaScript por defecto, mejora TTFB y convierte errores runtime en fallos de compilación mediante tipado.

    Cómo funciona (alto nivel): Server Islands difiere componentes dinámicos; Astro Actions expone funciones servidor/cliente tipadas; Content Layer mapea fuentes externas a colecciones validadas en build.

    Lo nuevo de Astro 6.2 y por qué lo tienes que probar: cambios clave

    Astro 6.2 no es una mejora cosmética. Afecta tres ejes que importan en producción: tiempo de entrega de HTML, seguridad y ergonomía del desarrollo, y cómo incorporas datos externos al proceso de build.

    • Mejoras en el servidor de desarrollo: resolución de módulos más rápida, arranques y HMR optimizados. Menos fricción en repos grandes o monorepos.
    • Server Islands estabilizadas: capacidad de diferir componentes server-side sin bloquear el TTFB.
    • Astro Actions: RPC tipado para mutaciones y formularios, con validación integrada.
    • Content Layer API: conectores para CMS, bases de datos o Notion, con validación y caching en build.

    Fuente oficial y changelog: astro.build/blog/astro-620/

    Server Islands: reducir TTFB sin perder personalización

    El patrón Server Islands en 6.2 se vuelve practicable en entornos de producción. La idea es simple y poderosa: renderizas la estructura estática y cacheable en el CDN; los componentes dinámicos se resuelven de forma diferida e independiente.

    Ejemplo mínimo

    ---
    import UserAvatar from '../components/UserAvatar.astro';
    ---
    
    Cargando avatar…

    Consecuencia práctica: el TTFB de la página no depende de la latencia de la consulta más lenta. Para páginas con contenido mayoritariamente estático y pequeñas zonas de personalización (e-commerce, landing pages personalizadas), la ganancia es directa y repetible.

    Documentación Server Islands: docs.astro.build/en/guides/server-islands/

    Astro Actions: menos endpoints, menos errores tipográficos

    Astro Actions introduce una abstracción RPC que reduce boilerplate y errores de sincronía entre cliente y servidor. Defines la acción en el servidor con validación (Zod) y la llamas desde el formulario como si fuera una función.

    Servidor

    import { defineAction } from 'astro:actions';
    import { z } from 'astro:schema';
    
    export const server = {
      subscribe: defineAction({
        input: z.object({ email: z.string().email() }),
        handler: async ({ email }) => {
          await db.insert({ email });
          return { success: true };
        },
      }),
    };
    

    Cliente (form)

    <form method="POST" action={actions.subscribe}>
      <input type="email" name="email" required />
      <button type="submit">Suscribirse</button>
    </form>
    

    Ventaja: si cambias el esquema, la compilación en el cliente falla. Eso convierte errores que antes aparecían en runtime en fallos de compilación, lo que mejora la confiabilidad y acelera el feedback loop.

    Guía de Actions: docs.astro.build/en/guides/actions/

    Content Layer API: datos externos como primera clase

    La Content Layer API en 6.2 permite tratar datos externos (CMS headless, Notion, bases SQL, APIs) como si fueran archivos locales durante el build. Tienes validación tipada, relaciones entre colecciones y caché inteligente.

    Arquitectónicamente significa desacoplar la fuente de contenido de la presentación sin perder seguridad en tipos y esquemas. Para equipos que manejan contenido editorial, marketing o documentación técnica, esto reduce fricción entre productores de contenido y desarrolladores.

    Docs Content Layer: docs.astro.build/en/guides/content-collections/

    ¿Cuándo adoptar Astro 6.2 y cuándo no?

    Adóptalo si:

    • Construyes sitios donde el SEO y Core Web Vitals son críticos (e-commerce, medios, docs).
    • Quieres reducir JavaScript enviado por defecto y solo hidratar lo necesario.
    • Necesitas un puente entre contenido diverso (Notion, CMS) y renderizado tipado en build.

    No es la mejor elección si:

    • Construyes aplicaciones con estado complejo y alta interactividad en cliente (editores colaborativos, apps en tiempo real intensivas).
    • Tu equipo necesita mantener un único modelo mental SPA sin fragmentar la responsabilidad entre server y client.

    Integración práctica: checklist rápido

    1. Prueba en un proyecto piloto: migra una página de marketing o un listado de productos.
    2. Instrumenta Server Islands en componentes con latencia (perfilado DB, llamadas externas).
    3. Usa Astro Actions en formularios y mutaciones sencillas para comprobar el feedback tipado.
    4. Conecta una fuente externa con Content Layer y valida el cacheo y el tiempo de build.
    5. Añade validaciones en CI para evitar regressiones en las APIs internas.

    Conclusión técnica

    Astro 6.2 madura un enfoque: menos JavaScript por defecto, más control en el servidor, y herramientas para que la mutación de datos y el contenido externo no sean fuentes de fragilidad. No es una panacea, pero sí una palanca técnica que reduce costes operativos y mejora métricas críticas. Pruébalo en un caso real y decide con datos, no con intuiciones. Repositorio y más referencias: github.com/withastro/astro

    FAQ

    ¿Qué mejora principalmente Astro 6.2?

    Mejora la entrega de HTML (TTFB), introduce RPC tipado para mutaciones (Astro Actions) y consolida una Content Layer para tratar fuentes externas con validación y cache en build.

    ¿Cómo reducen las Server Islands el TTFB?

    Separando el HTML estático (entregable y cacheable) de los componentes dinámicos que se hidratan o resuelven de forma diferida, la latencia de llamadas lentas no bloquea el primer byte retornado.

    ¿Qué son las Astro Actions y por qué usarlas?

    Son una abstracción RPC tipada que permite definir acciones en el servidor con validación y llamarlas desde formularios o cliente como si fueran funciones, reduciendo endpoints y errores de sincronía.

    ¿Qué tipos de fuentes puedo conectar con Content Layer?

    CMS headless, Notion, bases SQL y APIs; la Content Layer las trata como colecciones locales durante el build con validación tipada y caching inteligente.

    ¿Cuándo no es recomendable migrar a Astro 6.2?

    No es ideal para aplicaciones con estado complejo e interactividad intensa en cliente (por ejemplo editores colaborativos o apps en tiempo real que dependen de una mentalidad SPA única).

    ¿Dónde encuentro documentación y changelog?

    La nota de lanzamiento y el changelog están en astro.build/blog/astro-620/. La documentación de características específicas está en las guías: Server Islands, Actions y Content Collections en docs.astro.build.