O Astro desafia o status quo dos frameworks modernos ao priorizar HTML estático e isolar a interatividade em ilhas de código independentes.

Todo framework carrega uma aposta sobre o que a web deveria ser. React apostou em componentes e estado. Next.js apostou em renderização híbrida centrada em aplicações. O Astro fez uma aposta diferente: a maior parte do que colocamos na tela nunca precisou de JavaScript, então o framework deveria começar do zero absoluto de código no cliente e só adicionar o que for estritamente necessário.
Essa frase resume o projeto inteiro. O Astro é um framework para construir sites orientados a conteúdo — blogs, documentação, e-commerce, marketing, portfólios — que compila páginas em HTML estático por padrão e só envia JavaScript para o navegador quando um componente explicitamente pede interatividade.
Frameworks como React, Vue e Svelte nasceram para construir aplicações: dashboards, ferramentas internas, produtos SaaS. Quando usados para montar um site de conteúdo, eles carregam consigo um custo que não combina com o problema — o runtime inteiro do framework, o hidratador, o roteador, muitas vezes dezenas ou centenas de kilobytes de JavaScript, mesmo que 90% da página seja texto estático. Esse excesso tem nome: a "taxa de JavaScript" que o usuário paga antes de conseguir interagir com uma página que, na prática, quase não precisa de interação nenhuma.
O Astro inverte a pergunta. Em vez de "como faço essa aplicação JavaScript renderizar também no servidor", ele pergunta "como eu mantenho a página em HTML puro e abro exceções pontuais para JavaScript". A diferença parece sutil, mas muda a arquitetura inteira do framework.
Essa decisão resolve um segundo problema, tão real quanto o primeiro, embora raramente discutido no mesmo fôlego: o custo de servir conteúdo para quem lê sem executar JavaScript. Cada vez mais desse tráfego não vem de um navegador com um humano do outro lado, e sim de agentes de IA — crawlers de treinamento, sistemas de busca que respondem em tempo real, assistentes que navegam páginas em nome de alguém. Esse tipo de cliente não espera hidratação e não roda scripts: ele lê o HTML que chega e extrai dali o que precisa. Uma página que já nasce como HTML limpo e completo, sem depender de JavaScript para existir, custa uma fração dos tokens para ser processada por esses agentes — a mesma arquitetura que elimina o excesso de JavaScript para o navegador reduz, pelo mesmo motivo estrutural, o custo de leitura por máquina. É o mesmo pilar, servindo dois públicos.
O termo "component island" foi cunhado em 2019 por Katie Sylor-Miller, então arquiteta de front-end do Etsy, e detalhado no ano seguinte por Jason Miller, criador do Preact. O Astro foi o primeiro framework mainstream a construir esse padrão como base de sua arquitetura, e não como otimização posterior.
A ideia central: a página é renderizada quase inteiramente como HTML estático no build ou no servidor. Dentro dela, certos componentes — as ilhas — são isolados e hidratados individualmente no cliente, cada um com seu próprio pedaço de JavaScript, independente dos demais. Uma ilha não sabe que a outra existe, a menos que você explicitamente as conecte.
Isso resolve dois problemas ao mesmo tempo:
Payload mínimo. Se a página tem um carrossel de imagens e um formulário de newsletter, só o JavaScript desses dois componentes é enviado — não o framework inteiro, não o roteador, não a lógica de hidratação de partes que já são HTML morto.
Isolamento de falhas e de framework. Como cada ilha hidrata de forma independente, é possível ter um carrossel em Svelte e um formulário em React na mesma página, cada um dentro de seu próprio limite. O Astro nasceu agnóstico de framework de UI e continua assim.

O ganho fica claro quando se compara o payload lado a lado: numa SPA tradicional, o usuário paga o custo de runtime, roteador e hidratação antes mesmo de poder interagir com uma página que, na prática, é majoritariamente texto. No Astro, esse custo praticamente desaparece — o HTML é a saída natural do framework, não uma etapa intermediária a caminho do JavaScript.
Na prática, uma página Astro tem esta cara:
---// src/pages/index.astro// Este bloco roda apenas no servidor/build. Nunca chega ao navegador.import Layout from '../layouts/Layout.astro';import Newsletter from '../components/Newsletter.jsx'; // componente Reactimport Contador from '../components/Contador.astro';const produtos = await fetch('https://api.loja.com/produtos').then(r => r.json());---<Layout title="Loja Astro"> <h1>Catálogo</h1> <ul> {produtos.map((p) => ( <li>{p.nome} — R$ {p.preco.toFixed(2)}</li> ))} </ul> <!-- Ilha de interatividade: só este componente envia JS ao cliente --> <Newsletter client:visible /></Layout>Repare no que acontece aqui: a lista de produtos é buscada no servidor e renderizada como HTML puro — nenhum JavaScript de listagem chega ao navegador. O componente Newsletter, escrito em React, é a única ilha da página, e ela só é hidratada quando entra na viewport, graças à diretiva client:visible.
O que torna a arquitetura de ilhas prática, e não apenas conceitual, é o conjunto de diretivas client:* que controlam quando e como cada ilha ganha vida no navegador:
Diretiva | Quando hidrata |
|---|---|
| Imediatamente, assim que a página carrega |
| Quando o navegador estiver ocioso ( |
| Quando o componente entra na viewport ( |
| Quando um media query CSS é satisfeito (ex.: só em telas grandes) |
| Renderiza somente no cliente, pulando o HTML do servidor |

Essa granularidade é o que separa o Astro de uma simples "SSG com React embutido". Um site típico de e-commerce pode ter um menu que hidrata com client:idle (não é crítico), um carrinho de compras com client:load (crítico desde o primeiro momento) e um widget de recomendações que só hidrata com client:visible, porque o usuário pode nem rolar até ele.
Em 2024 o Astro introduziu as Server Islands, que estendem essa lógica para o servidor: um componente pode ser marcado como adiado, com um HTML de fallback enviado imediatamente enquanto o servidor busca dados dinâmicos ou por usuário (um contador de carrinho, uma saudação personalizada) em segundo plano, sem bloquear o restante da página. Isso resolve uma limitação clássica das ilhas clássicas: páginas com algum trecho que depende de dados por requisição já não precisam escolher entre esperar tudo ou jogar tudo para o cliente.
Nenhuma arquitetura resolve todos os problemas igualmente bem — e um artigo técnico que promete o contrário não merece confiança. A separação entre onde a aposta do Astro compensa e onde ela cobra um preço começa aqui, sem meio-termo.
Performance por padrão. Como o HTML é a saída natural do framework e o JavaScript é opt-in, projetos Astro tendem a começar com métricas de Core Web Vitals — LCP, TBT, CLS — sensivelmente melhores do que equivalentes em frameworks centrados em SPA, sem que o time precise configurar nada de especial para isso. A frase que resume a filosofia, retirada da própria documentação do projeto, é direta: deveria ser quase impossível construir um site lento com o Astro.
SEO. Motores de busca indexam HTML renderizado; conteúdo que depende de hidratação no cliente para aparecer é historicamente mais arriscado para rastreamento e indexação, mesmo com as melhorias recentes dos crawlers. Como o Astro entrega HTML completo por padrão — sem depender de JavaScript para o conteúdo principal existir — o SEO técnico vem de graça, sem exigir estratégias paralelas de renderização.
Um contraponto se impõe aqui, porque é fácil exagerar a diferença. Frameworks como o Next.js, com App Router e Server Components, também são capazes de entregar HTML completo e bem indexável — a diferença não está em "quem consegue" SEO forte, mas em quanto esforço é preciso para chegar lá. No Astro, HTML pronto é o caminho de menor resistência: é o que acontece quando você não faz nada de especial. No Next.js, o mesmo resultado depende de decisões corretas ao longo do caminho — cuidado com o limite de "use client", atenção a quando generateMetadata depende de dados dinâmicos como cookies ou headers (o que pode virar gargalo e atrasar os metadados se não for tratado, como discutimos na Seção 4.4 sobre PPR), e garantia de que conteúdo dentro de um <Suspense> não fique ausente para crawlers que não esperam o streaming terminar.
Na prática, o Google e os crawlers mais importantes hoje executam JavaScript e resolvem streaming razoavelmente bem, então a diferença de indexação pura tende a ser menor do que era há alguns anos. Mas motores de busca menores, bots que geram preview de link (Open Graph, Twitter Cards), scrapers de SEO técnico e ferramentas de monitoramento — que frequentemente não executam JavaScript — continuam se beneficiando muito mais de HTML pronto de imediato. É por isso que um teste rápido em Astro costuma "parecer" mais nativo: ele não é tecnicamente impossível de igualar em outro framework, mas é o resultado padrão em vez de um objetivo que precisa ser configurado.
Zero framework lock-in na camada de UI. Um projeto pode ter componentes .astro, React, Vue, Svelte e Solid coexistindo. Isso viabiliza migrações incrementais: uma equipe que quer sair de um stack legado pode reescrever seção por seção, sem parar tudo para uma reescrita completa.
Content Collections com tipagem. Para sites com muito conteúdo em Markdown/MDX, o Astro oferece um sistema de coleções tipadas via Zod, em que o schema do frontmatter é validado em tempo de build. Um campo de data escrito errado ou um título ausente vira erro de build, não bug em produção.
Portabilidade de deploy. Adaptadores oficiais para Node, Cloudflare, Vercel, Netlify e Deno colocam o Astro numa posição relativamente neutra em relação a provedor — importante para equipes que não querem acoplar a arquitetura de front-end a um único serviço de hospedagem.
Aqui é onde a honestidade técnica importa mais do que o entusiasmo de lançamento.
Aplicações altamente interativas sofrem com o modelo de ilhas. Um dashboard analítico com dezenas de widgets conectados por estado compartilhado, atualizações em tempo real via WebSocket e navegação client-side densa é exatamente o cenário em que a arquitetura de ilhas — pensada para isolamento — começa a trabalhar contra você. Ilhas são independentes por design; orquestrar estado global entre múltiplas ilhas exige soluções externas (nanostores, Zustand exposto via window, um event bus) que o React ou o Vue resolveriam nativamente com um único Context ou store.
O parágrafo anterior descreveu o problema em abstrato; vale ver a solução em código, porque é aqui que a teoria se torna decisão de engenharia. Concretamente: um botão "Adicionar ao carrinho", escrito em React, precisa avisar um widget de carrinho, escrito em Vue, de que um item foi adicionado. As duas ilhas rodam em árvores de renderização completamente separadas — não existe um Context do React ou uma provide/inject do Vue que atravesse essa fronteira, porque, tecnicamente, não existe uma árvore de componentes única unindo as duas.
É exatamente esse o problema que a documentação oficial do Astro recomenda resolver com Nanostores: uma biblioteca de gerenciamento de estado atômico, agnóstica de framework, que vive fora de qualquer árvore de renderização. Um store do Nanostores não pertence ao React nem ao Vue — ele é só um objeto JavaScript em memória, no navegador, que qualquer ilha pode importar e assinar. Cada framework se conecta a ele por meio de um adaptador fino (@nanostores/react, @nanostores/vue), mas o estado em si não sabe, e não precisa saber, quem está ouvindo.

Instalar o Nanostores e os adaptadores
npm install nanostores @nanostores/react @nanostores/vuenpx astro add vueCriar o store compartilhado, fora de qualquer componente
// src/stores/carrinho.tsimport { atom } from 'nanostores';export interface ItemCarrinho { id: string; nome: string; quantidade: number;}// Este atom não pertence a nenhum framework. É só estado em memória,// vivendo fora de qualquer árvore de renderização — React ou Vue.export const $carrinho = atom<ItemCarrinho[]>([]);export function adicionarAoCarrinho(item: Omit<ItemCarrinho, 'quantidade'>) { const atual = $carrinho.get(); const existente = atual.find((i) => i.id === item.id); if (existente) { $carrinho.set( atual.map((i) => i.id === item.id ? { ...i, quantidade: i.quantidade + 1 } : i ) ); } else { $carrinho.set([...atual, { ...item, quantidade: 1 }]); }}A ilha React que escreve no store
// src/components/BotaoAdicionar.tsximport { adicionarAoCarrinho } from '../stores/carrinho';interface Props { id: string; nome: string;}export default function BotaoAdicionar({ id, nome }: Props) { return ( <button onClick={() => adicionarAoCarrinho({ id, nome })}> Adicionar {nome} ao carrinho </button> );}Este componente nem precisa do hook useStore — ele só chama a função adicionarAoCarrinho, que atualiza o store. Ele escreve no estado global, mas não precisa lê-lo.
A ilha Vue que lê e reage ao store
<!-- src/components/WidgetCarrinho.vue --><script setup lang="ts">import { useStore } from '@nanostores/vue';import { $carrinho } from '../stores/carrinho';// useStore(), do adaptador Vue, transforma o atom do Nanostores// em um `ref` reativo do Vue — sem que o Vue precise saber// que o estado nasceu fora do seu próprio sistema de reatividade.const carrinho = useStore($carrinho);</script><template> <aside class="widget-carrinho"> <h3>Carrinho ({{ carrinho.length }})</h3> <ul> <li v-for="item in carrinho" :key="item.id"> {{ item.nome }} × {{ item.quantidade }} </li> </ul> </aside></template>Combinando as duas ilhas na mesma página
---// src/pages/loja.astroimport Layout from '../layouts/Layout.astro';import BotaoAdicionar from '../components/BotaoAdicionar.tsx';import WidgetCarrinho from '../components/WidgetCarrinho.vue';---<Layout title="Loja"> <main> <h1>Catálogo</h1> <!-- Ilha 1: React. Só escreve no store. --> <BotaoAdicionar id="prod-1" nome="Teclado" client:load /> <BotaoAdicionar id="prod-2" nome="Mouse" client:load /> <!-- Ilha 2: Vue. Só lê e reage ao store. --> <WidgetCarrinho client:load /> </main></Layout>Ao clicar em "Adicionar Teclado ao carrinho", nenhuma das duas ilhas conversa diretamente com a outra, e nenhuma delas sabe que a outra existe. O que acontece é isto: o componente React chama adicionarAoCarrinho, que atualiza o atom do Nanostores; o atom, por sua vez, emite um evento de mudança; o adaptador @nanostores/vue, que está com uma assinatura ativa através de useStore, recebe essa notificação e marca o ref reativo do Vue como alterado; o Vue, seguindo seu próprio ciclo de reatividade normal, re-renderiza o <WidgetCarrinho> — tudo isso sem que React e Vue tenham qualquer conhecimento um do outro.
Esse é o ponto que vale reter: o Nanostores não é uma ponte entre React e Vue — é um terceiro lugar, neutro, fora de ambas as árvores de renderização, para onde os dois frameworks olham de forma independente. É a mesma filosofia da arquitetura de ilhas aplicada ao problema de estado: em vez de forçar duas ilhas a se conhecerem, cria-se um ponto de verdade compartilhado que nenhuma delas precisa "possuir".
Sem roteamento client-side nativo com estado preservado. Diferente de uma SPA, a navegação padrão do Astro recarrega o documento — o View Transitions API do Astro suaviza essa transição visualmente, mas o modelo mental continua sendo o de páginas, não o de uma aplicação de página única com estado de memória persistente entre rotas.
Autenticação e sessão exigem mais trabalho manual. Next.js, por ter middleware, server actions e um ecossistema mais maduro em torno de autenticação (NextAuth/Auth.js foi construído pensando nele primeiro), reduz a distância entre "preciso de login" e "login funcionando". No Astro, isso normalmente significa integrar bibliotecas externas e escrever a lógica de sessão à mão.
Ecossistema de plugins menor. O Astro é mais novo e mais nichado que React/Next.js. Para funcionalidades muito específicas, a chance de encontrar uma integração pronta e madura é menor, e a equipe frequentemente precisa escrever a ponte por conta própria.
Curva de decisão sobre "quanto de aplicação" o projeto tem. Projetos híbridos — um site majoritariamente estático com uma seção de aplicação completa (por exemplo, um painel de cliente logado) — obrigam a equipe a decidir onde termina o "site Astro" e começa a "aplicação React embutida". Essa costura, quando mal planejada, gera duas bases de código concorrendo pela mesma responsabilidade.
Uma regra prática, adotada por times experientes: se a pergunta "isso é conteúdo ou é aplicação?" tiver resposta clara e for majoritariamente "conteúdo", o Astro tende a compensar. Se a resposta for "aplicação densa, com muito estado compartilhado e interações em tempo real", frameworks como Next.js, Remix ou uma SPA em React puro resolvem com menos atrito. Muitos projetos reais, no entanto, são os dois ao mesmo tempo — e é exatamente aí que entram as seções seguintes.
O Astro não implementa seu próprio bundler. Ele é construído sobre o Vite, usando-o para dev server, HMR (Hot Module Replacement) e build de produção via Rollup. Isso significa que grande parte do ecossistema de plugins Vite funciona dentro de um projeto Astro sem adaptação, e que a experiência de desenvolvimento — recarregamento quase instantâneo, pre-bundling de dependências — é herdada diretamente do Vite.
Configurar o Astro é, em boa medida, configurar Vite com uma camada adicional por cima:
// astro.config.mjsimport { defineConfig } from 'astro/config';import react from '@astrojs/react';import tailwind from '@astrojs/tailwind';export default defineConfig({ integrations: [react(), tailwind()], vite: { // Qualquer opção válida de Vite pode ser passada aqui resolve: { alias: { '@': '/src' }, }, },});A integração @astrojs/react é a ponte mais usada entre o modelo de ilhas e o ecossistema React. A instalação registra o renderer necessário para o Astro saber como hidratar componentes .jsx/.tsx como ilhas:
npx astro add reactIsso adiciona a integração ao astro.config.mjs e instala react, react-dom e @astrojs/react automaticamente. A partir daí, qualquer componente React pode ser importado em um arquivo .astro e receber uma diretiva client:*:
// src/components/Contador.tsximport { useState } from 'react';interface ContadorProps { valorInicial?: number;}export default function Contador({ valorInicial = 0 }: ContadorProps) { const [contagem, setContagem] = useState(valorInicial); return ( <div className="contador"> <button onClick={() => setContagem((c) => c - 1)}>-</button> <span>{contagem}</span> <button onClick={() => setContagem((c) => c + 1)}>+</button> </div> );}---// src/pages/produto/[id].astroimport Contador from '../../components/Contador.tsx';---<html lang="pt-BR"> <body> <h1>Produto</h1> <!-- Só este componente carrega React no navegador, e só quando visível --> <Contador valorInicial={1} client:visible /> </body></html>Note o detalhe: props passadas de .astro para o componente React são serializadas e reidratadas no cliente. Funções e objetos não serializáveis não atravessam essa fronteira — um erro comum de quem vem de um projeto 100% React é tentar passar um callback complexo direto de um contexto de servidor.
O suporte a TypeScript é de primeira classe: arquivos .astro aceitam a frontmatter fence (---) com código TypeScript diretamente, e o Astro gera checagem de tipos via astro check. Configurar tsconfig.json corretamente é o que garante que erros de tipo apareçam antes do deploy, não depois:
{ "extends": "astro/tsconfigs/strict", "compilerOptions": { "jsx": "react-jsx", "baseUrl": ".", "paths": { "@/*": ["src/*"] } }}Componentes .tsx (React) e .astro compartilham o mesmo grafo de tipos quando bem configurados — props tipadas por interface ou type são checadas na fronteira entre os dois mundos, o que reduz uma classe inteira de bugs de integração:
// src/types/produto.tsexport interface Produto { id: string; nome: string; preco: number; estoque: number;}---import type { Produto } from '../types/produto';import CardProduto from '../components/CardProduto.tsx';const produtos: Produto[] = await fetch('/api/produtos').then(r => r.json());---{produtos.map((produto) => ( <CardProduto produto={produto} client:visible />))}É tentador tratar Astro e Next.js como concorrentes diretos na mesma prateleira, mas eles otimizam para problemas diferentes:
Critério | Astro | Next.js |
|---|---|---|
Modelo mental padrão | Site multi-página, HTML primeiro | Aplicação React, com App Router e Server Components |
JavaScript enviado por padrão | Zero, exceto ilhas explícitas | Depende da árvore de componentes e do uso de |
Melhor encaixe | Conteúdo, marketing, documentação, blogs, e-commerce de catálogo | Dashboards, SaaS, produtos com autenticação e estado complexo |
Framework de UI | Agnóstico (React, Vue, Svelte, Solid, Preact) | React apenas |
Roteamento client-side | Limitado (View Transitions suaviza, mas não é SPA completo) | Nativo e profundo (App Router, streaming, parallel routes) |
Ecossistema de autenticação/sessão | Requer integração manual | Maduro (Auth.js nasceu majoritariamente para esse contexto) |
A conclusão prática que times de engenharia experientes vêm adotando não é "qual framework é melhor", mas "qual pergunta arquitetural este projeto está fazendo". Um site institucional com uma área de blog não precisa do Router de aplicação do Next.js. Um SaaS com autenticação, permissões e estado de sessão complexo dificilmente se beneficia de recomeçar do zero em cima de ilhas. É comum, inclusive, ver as duas ferramentas convivendo na mesma organização, cada uma no domínio em que compensa.
Antes de entrar nesta seção, vale situar o terreno: o que vem a seguir resolve um problema muito específico, e reconhecer esse problema é o que decide se ele é seu. A pergunta não é "o Astro suporta micro frontends?" — suporta, e bem. A pergunta certa é outra: sua organização já tem múltiplos times que precisam, por razão de escala ou de estrutura, de ciclos de deploy independentes para partes diferentes da mesma experiência de usuário? Se a resposta for sim, o restante desta seção é o mapa de como fazer isso funcionar sem armadilhas. Se a resposta for não, ela continua sendo útil — porque entender onde fica essa fronteira é o que evita que uma equipe complique o próprio deploy resolvendo um problema organizacional que nunca teve.
Micro frontends aplicam à camada de UI a mesma lógica das microsserviços no back-end: dividir uma aplicação grande em unidades independentes, desenvolvidas e implantadas por equipes diferentes, compostas depois em uma experiência única — normalmente coordenada por uma aplicação "casca" (shell). Isso resolve problemas reais de organizações grandes: times que não conseguem mais compartilhar um único repositório sem pisar uns nos outros, ciclos de deploy que precisam ser independentes, ou stacks tecnológicos diferentes convivendo por necessidade de migração gradual.
Historicamente, compor micro frontends renderizados no servidor (SSR) era considerado complexo — normalmente resolvido com Server-Side Includes, Edge-Side Includes ou composição via Ajax, técnicas que exigem infraestrutura de borda dedicada. É exatamente nesse ponto que a arquitetura de ilhas do Astro se torna interessante como solução, e não apenas como estilo.
A forma mais natural de aplicar o modelo do Astro a micro frontends é tratar cada ilha como o limite de propriedade de um time. Uma aplicação "casca" em Astro define o layout, a navegação e o esqueleto compartilhado; cada equipe entrega um componente (React, Vue, Svelte — o que fizer sentido para o seu time) que vira uma ilha isolada dentro desse layout:
---// src/pages/dashboard.astro — a "casca" (shell)import Layout from '../layouts/Shell.astro';import PainelVendas from '../components/times/vendas/PainelVendas.tsx';import PainelSuporte from '../components/times/suporte/PainelSuporte.vue';import PainelEstoque from '../components/times/estoque/PainelEstoque.svelte';---<Layout titulo="Painel Operacional"> <!-- Cada painel é entregue e versionado por um time diferente --> <section aria-label="Vendas"> <PainelVendas client:visible /> </section> <section aria-label="Suporte"> <PainelSuporte client:visible /> </section> <section aria-label="Estoque"> <PainelEstoque client:idle /> </section></Layout>Como cada ilha hidrata isoladamente, times diferentes podem usar frameworks diferentes sem que um vaze para o outro — algo que uma SPA monolítica dificilmente permite sem ferramentas adicionais como Module Federation.
A limitação da Estratégia 1 é que ela ainda pressupõe um único repositório (ou pelo menos um único processo de build) reunindo todas as ilhas. Para micro frontends de verdade — com deploys independentes, cada um servido por sua própria origem — o recurso relevante são as Server Islands, que permitem que um componente seja buscado e renderizado no servidor de forma assíncrona, com fallback imediato, sem que a página inteira precise esperar por ele:
---// src/components/FragmentoRemoto.astroexport const prerender = false;interface Props { endpoint: string;}const { endpoint } = Astro.props;// Busca HTML já renderizado por outro serviço/time, em outra origemconst resposta = await fetch(endpoint, { headers: { 'x-solicitante': 'shell-astro' },});const html = await resposta.text();---<div class="fragmento-remoto" set:html={html} />---// src/pages/index.astroimport FragmentoRemoto from '../components/FragmentoRemoto.astro';---<main> <h1>Portal Corporativo</h1> <!-- Renderiza no servidor, sem bloquear o restante da página --> <FragmentoRemoto server:defer endpoint="https://times-marketing.empresa.com/api/fragmento" > <div slot="fallback">Carregando promoções…</div> </FragmentoRemoto></main>Esse padrão aproxima o Astro do modelo clássico de composição via Edge-Side Includes, mas sem exigir infraestrutura de borda dedicada — a composição acontece no próprio servidor Astro, com a vantagem de um fallback declarativo e streaming de HTML.
Um parêntese cabe aqui, porque é comum — e revelador — perceber que o Next.js chegou a uma ideia muito parecida por um caminho diferente. O Partial Prerendering (PPR), que se tornou estável no Next.js 16 (outubro de 2025) como parte do recurso Cache Components, resolve exatamente o mesmo problema que as Server Islands do Astro: como servir um shell estático instantâneo e, ao mesmo tempo, incluir trechos dinâmicos e personalizados sem bloquear a página inteira.
A mecânica é diferente, mas o resultado visível é quase idêntico. Em vez de uma diretiva própria como server:defer, o PPR usa o <Suspense> do próprio React como fronteira: tudo fora de um Suspense é renderizado no build e vira o shell estático, cacheável em CDN; tudo dentro de um Suspense é tratado como dinâmico, roda como Server Component no momento da requisição, e é transmitido (streamed) para dentro do mesmo HTML, preenchendo o fallback declarado assim que os dados chegam:
// app/dashboard/page.tsx — Next.js com PPRimport { Suspense } from 'react';import { SaudacaoUsuario, EsqueletoSaudacao } from './saudacao';export const experimental_ppr = true;export default function Pagina() { return ( <section> <h1>Isto é pré-renderizado no build</h1> <Suspense fallback={<EsqueletoSaudacao />}> {/* Isto usa cookies()/headers() e só pode rodar por requisição */} <SaudacaoUsuario /> </Suspense> </section> );}---// index.astro — Astro com Server Islandsexport const prerender = false;---<section> <h1>Isto é pré-renderizado no build</h1> <SaudacaoUsuario server:defer> <div slot="fallback">Carregando saudação…</div> </SaudacaoUsuario></section>Postos lado a lado, os dois trechos contam a mesma história com vocabulários diferentes: um shell estático que chega instantaneamente, um limite explícito ao redor do que é dinâmico, um fallback que aparece primeiro, e o conteúdo real chegando via streaming dentro da mesma resposta HTTP — sem uma segunda requisição do cliente. A diferença estrutural está em quem decide o limite: no Astro, você declara explicitamente server:defer componente a componente, como uma decisão de composição; no Next.js, o limite nasce do próprio modelo de Server Components e Suspense do React, e o build falha com um erro se você usar uma API dinâmica (cookies(), headers()) fora de um Suspense — o framework força a fronteira, em vez de sugeri-la.
Para quem vem do mundo React, essa proximidade é o motivo mais comum de curiosidade pelo Astro: se o PPR já mostrou, dentro do ecossistema Next.js, que "estático por padrão com furos dinâmicos declarados" é um modelo mental que funciona bem em produção, o Astro oferece exatamente essa mesma filosofia — porém como ponto de partida da arquitetura inteira, não como um recurso opcional dentro de um framework pensado primeiro para aplicações. Onde o PPR "escapa" da renderização 100% de aplicação SPA para ganhar velocidade, o Astro parte do zero estático e "escapa" para dinamismo só quando pedido — dois caminhos opostos convergindo para a mesma ideia central.
É importante não vender essa estratégia como solução pronta e definitiva. A própria equipe do Astro discute publicamente, em seu repositório de roadmap, o cenário de compor fragmentos vindos de múltiplos servidores Astro independentes na mesma página — e reconhece que isso pode gerar conflitos de estado global, elementos ou eventos no lado do cliente quando cada fragmento carrega sua própria hidratação sem coordenação entre origens. Ou seja: o Astro resolve bem a composição de ilhas dentro de uma única aplicação/shell, mas compor múltiplas aplicações Astro independentes, cada uma com seu próprio ciclo de vida de JavaScript no cliente, ainda exige convenções manuais — nomes configuráveis para elementos e eventos globais, isolamento de CSS, e cuidado para que duas ilhas de origens diferentes não colidam por acidente.
Mas a limitação mais subestimada não é técnica — é operacional, e ela merece sair das entrelinhas. A autonomia de UI que a arquitetura de ilhas promete tem uma contrapartida real em infraestrutura, e essa conta chega antes da primeira linha de código de fragmento remoto.
Um cenário concreto ajuda a tirar isso do plano das ideias. Imagine um e-commerce dividido em dois times autônomos: o time de Catálogo trabalha em Vue e publica seus artefatos no servidor A; o time de Carrinho trabalha em React e publica no servidor B. Cada um decide sua própria stack, seu próprio ritmo de deploy — a promessa de autonomia, cumprida à risca. Só que, para o usuário final, isso precisa parecer um único site, num único domínio. Alguém, na borda da rede, precisa decidir qual requisição vai para onde:
# Configuração simplificada de edge routerroute "/produtos/*" -> origem_A # servidor do time de Catálogo (Vue)route "/carrinho/*" -> origem_B # servidor do time de Carrinho (React)route "/*" -> shell # aplicação Astro que compõe o resultado finalIsso parece trivial até o momento em que o servidor B, o do carrinho, sofre um atraso de oitocentos milissegundos — um pico de tráfego, uma consulta lenta ao banco, não importa a causa. Esse atraso não fica isolado dentro do time de Carrinho: ele vaza para qualquer página que componha um fragmento vindo da origem B. Se a página de produto do Catálogo mostra um resumo do carrinho no canto da tela, essa página inteira passa a esperar os oitocentos milissegundos do serviço mais lento da composição — mesmo que o Catálogo não tenha mudado uma linha de código. É esse acoplamento invisível, entre times que juraram estar desacoplados, que a lista de responsabilidades abaixo tenta nomear uma por uma.
O reverse proxy ou edge router deixa de ser opcional. No momento em que "vários times, várias origens" vira "um único domínio para o usuário final", alguém precisa decidir, por requisição, qual origem responde a qual rota — e esse alguém é, invariavelmente, uma camada de roteamento na frente de tudo: Nginx, um API Gateway, ou um edge router rodando em CDN (Cloudflare Workers, Lambda@Edge, Akamai EdgeWorkers). Essa camada não é um detalhe de configuração — ela vira uma peça de infraestrutura com dono, versionamento e SLA próprios. Ela precisa saber, por prefixo de caminho ou por regra de negócio, se /estoque vai para o servidor Astro do time A e /vendas para o do time B; precisa lidar com regras de cache diferentes por origem (o fragmento de vendas pode mudar a cada minuto, o de estoque uma vez por hora); e, quando o próprio Astro busca um fragmento remoto via server:defer, esse fetch também passa — ou deveria passar — por esse mesmo roteador, para herdar as mesmas políticas de timeout, retry e cabeçalhos de autenticação entre serviços.
CORS e propagação de cabeçalhos deixam de ser um problema raro. Quando um Server Island faz fetch para uma origem diferente da que serviu a página, você herda, de forma explícita, os mesmos problemas de qualquer chamada entre serviços: cabeçalhos de autenticação que precisam ser repassados (ou re-emitidos) na fronteira, políticas de CORS quando a composição não acontece inteiramente no servidor, e um orçamento de latência que agora depende da origem mais lenta da cadeia — se o fragmento remoto demora 800ms para responder, o fallback fica visível por 800ms, não importa quão rápido o shell tenha sido.
O CI/CD deixa de ser "um pipeline" e vira "N pipelines com um contrato entre eles". Cada micro frontend — cada aplicação Astro independente, no cenário de múltiplos servidores — ganha, na prática, seu próprio pipeline de build, teste e deploy, o que é exatamente o ponto de ter equipes autônomas. O custo aparece na coordenação entre eles: o shell precisa continuar funcionando mesmo quando um fragmento publica uma versão nova e incompatível, o que empurra a equipe para práticas como contract testing entre shell e fragmentos, feature flags para liberar uma nova versão gradualmente, canary releases para limitar o raio de impacto de um fragmento com bug, e observabilidade que consiga rastrear uma falha até a origem certa quando o problema aparece só na composição final, não em nenhum dos fragmentos isolados. Nenhuma dessas práticas é exclusiva do Astro — são o preço de qualquer arquitetura de micro frontend renderizada no servidor —, mas é importante entrar nessa decisão sabendo que elas não são opcionais: sem elas, a autonomia de deploy vira instabilidade de produção.
Isso coloca o Astro em uma posição específica no espectro de micro frontends: mais simples e mais barato que Module Federation para cenários em que a composição acontece dentro de uma casca única e controlada; menos maduro que soluções dedicadas (single-spa, Module Federation do Webpack/Rspack) para cenários em que cada micro frontend é verdadeiramente autônomo, com seu próprio ciclo de deploy e origem, hidratando lado a lado sem coordenação central. E, em qualquer um dos dois cenários, a decisão de adotar micro frontends via Astro deveria ser tomada junto com quem vai operar o reverse proxy e os pipelines — não só com quem vai escrever os componentes.
Faz sentido considerar o Astro como base de micro frontends quando:
O conteúdo é majoritariamente renderizável no servidor, e a interatividade é localizada em componentes específicos, não na aplicação inteira.
Os times já trabalham (ou aceitam trabalhar) sob uma casca compartilhada, em vez de aplicações totalmente autônomas com origens e ciclos de deploy independentes.
SEO e performance de carregamento inicial são requisitos de primeira ordem — cenário comum em portais corporativos, e-commerce e sites institucionais compostos por múltiplos times.
Faz mais sentido evitar o Astro, ou usá-lo apenas como camada de apresentação sobre uma solução de composição mais robusta, quando:
Cada micro frontend precisa de deploy e origem totalmente independentes, com hidratação simultânea e isolada, sem um shell central coordenando tudo.
A aplicação é predominantemente interativa (dashboards, editores, ferramentas de produtividade), reduzindo a vantagem de "zero JS por padrão" a quase zero, já que quase tudo vira ilha de qualquer forma.
A organização não tem, hoje, um time ou uma prática consolidada de operar reverse proxy/edge router, observabilidade entre origens e coordenação de deploy entre pipelines independentes — porque, nesse caso, o custo de montar essa capacidade do zero costuma superar o ganho de autonomia de UI que motivou a decisão em primeiro lugar.
A mesma arquitetura que elimina o custo de JavaScript para humanos é exatamente a que reduz, em até dez vezes, os tokens consumidos por agentes de IA ao ler uma página. Essa não é uma coincidência de design nem um efeito colateral descoberto depois do lançamento — é a consequência direta de uma única decisão, tomada desde a primeira linha do Astro: estático por padrão, dinâmico só onde declarado. O que a Seção 1 apresentou como economia de JavaScript no navegador e a Seção 4 mostrou como um shell central entregando HTML coeso e completo é, olhando de outro ângulo, exatamente a infraestrutura que esse novo tipo de cliente mais valoriza.
Porque é isso que um crawler de IA é, tecnicamente: mais um cliente HTTP fazendo uma requisição contra o mesmo shell que serve um navegador — só que mais exigente. Ele não executa JavaScript, não espera hidratação, não navega clicando em links: faz uma requisição, recebe uma resposta, e extrai o que precisa dali, sem segunda chance. Se a saída desse shell já é HTML limpo e completo — a mesma composição descrita na Seção 4 — esse cliente não-humano recebe exatamente a vantagem que o Astro foi desenhado para entregar a humanos: nenhum ruído de scripts, nenhuma espera por hidratação, nenhuma dependência de execução de código para que o conteúdo exista.
Dito de forma direta: o Astro não precisou se adaptar para a era dos agentes de IA. Ele já estava pronto para ela antes de ela existir — o mesmo investimento arquitetural que serve bem um usuário humano paga dividendo duplo quando o "usuário" é uma máquina. Isso não isenta o framework de uma resposta honesta sobre como ele se comporta nesse cenário — não um slide de marketing. A resposta curta é que ele herda, quase de graça, essa vantagem estrutural — e ao mesmo tempo enfrenta uma área em rápida mudança onde nenhum framework, incluindo ele, tem ainda um padrão definitivo.
A maioria dos crawlers relevantes para IA — bots de treinamento como o GPTBot e o ClaudeBot, ou bots de indexação para respostas em tempo real como o OAI-SearchBot — não executa JavaScript de forma consistente nem paga o custo de esperar hidratação. Nesse sentido, eles se comportam como uma versão ainda mais exigente do cenário de composição que vimos na Seção 4: onde um humano tolera (até certo ponto) esperar uma ilha hidratar, um crawler de IA simplesmente não espera — ele lê o que chegou na resposta HTTP e segue em frente. Quando esses bots encontram uma página cheia de markup de navegação, scripts, anúncios e camadas de hidratação antes do conteúdo real, eles gastam janela de contexto e tempo de processamento em ruído. Empresas que passaram a servir Markdown limpo em vez de HTML denso relataram reduções de até 10 vezes no número de tokens necessários para processar a mesma página.
Como o Astro entrega HTML estático e semântico por padrão — a mesma característica que favorece SEO tradicional e que discutimos como base da composição de micro frontends —, um agente de IA que rastreia um site Astro tende a receber conteúdo limpo sem esforço extra, exatamente pelo mesmo motivo que um crawler de busca tradicional recebe. A vantagem não foi desenhada pensando em IA; ela é uma consequência colateral de uma arquitetura que já priorizava HTML pronto para qualquer cliente, humano ou não. Isso não é exclusividade do Astro — qualquer site majoritariamente estático se beneficia da mesma forma —, mas é coerente com o restante do artigo: no Astro, esse comportamento não exige configuração.
Surgiu em 2024 uma proposta de padrão chamada llms.txt — um arquivo em texto simples, na raiz do site, funcionando como um "sumário" legível por agentes: uma lista curada de páginas importantes, com links diretos para versões em Markdown. A ideia é sedutora e tecnicamente simples de implementar em Astro, já que gerar um endpoint de texto em build time é trivial:
// src/pages/llms.txt.tsimport { getCollection } from 'astro:content';export async function GET() { const posts = await getCollection('blog'); const linhas = posts.map( (post) => `- [${post.data.title}](/blog/${post.slug}.md): ${post.data.description}` ); const conteudo = [ '# Meu Site', '', '> Documentação e artigos técnicos.', '', '## Artigos', ...linhas, ].join('\n'); return new Response(conteudo, { headers: { 'Content-Type': 'text/plain; charset=utf-8' }, });}Mas a honestidade aqui importa: o entusiasmo em torno do llms.txt correu na frente dos dados. Em julho de 2025, a própria equipe de Search do Google declarou publicamente que não usa e não planeja usar o llms.txt como sinal — e chegou a compará-lo à extinta meta tag de keywords. Nenhum grande provedor de LLM (OpenAI, Anthropic, Google, Meta) assumiu publicamente o compromisso de tratar o arquivo como sinal de indexação ou de resposta. Levantamentos recentes mostram adoção em torno de 10% dos domínios analisados, e o tráfego de bots de treinamento e de busca com IA sobre o arquivo /llms.txt em si é, segundo análises de tráfego de bots, estatisticamente desprezível.
O que sobrevive dessa proposta, na prática, é um uso mais estreito do que o pretendido originalmente: o llms.txt está se firmando como camada de navegação para agentes de codificação — ferramentas como Cursor, Claude Code e GitHub Copilot, que buscam documentação técnica sob demanda enquanto ajudam um desenvolvedor —, e não como mecanismo de ranqueamento ou citação em buscas de IA voltadas ao público geral.
Um episódio recente ilustra bem o quanto esse terreno ainda está se movendo. A própria equipe do Astro, que havia sido pioneira em publicar um llms.txt em sua documentação oficial, removeu o arquivo em 2026. A justificativa dos mantenedores não foi falta de interesse por agentes de IA — pelo contrário: foi a avaliação de que um arquivo estático de texto já não era a melhor forma de atender esse público. Em seu lugar, o Astro passou a oferecer um servidor MCP (Model Context Protocol) para sua documentação, permitindo que ferramentas como o Claude Code consultem a documentação de forma interativa e estruturada, em vez de baixar um índice estático e tentar adivinhar o que é relevante.
Esse caso é uma lição de humildade técnica: o comportamento "correto" para preparar um site para agentes de IA ainda não é um padrão fechado — está sendo negociado em tempo real entre provedores de LLM, mantenedores de frameworks e a comunidade. O mesmo vale para este próprio artigo: escrito hoje, ele tem validade curta por definição.
Apesar da incerteza sobre qual padrão vai vencer, o ecossistema de integrações do Astro já reflete essa demanda concretamente. Hoje é possível encontrar, no diretório oficial de integrações, pacotes prontos que geram automaticamente, no momento do build:
Versões em Markdown de cada página, servidas junto ao HTML via negociação de conteúdo HTTP (Accept: text/markdown) ou por convenção de URL (/artigo.md ao lado de /artigo).
robots.txt com regras específicas por bot de IA, permitindo, por exemplo, autorizar o OAI-SearchBot (usado para respostas do ChatGPT) e bloquear o GPTBot (usado para treinamento de modelos) separadamente — os grandes provedores hoje operam bots distintos para cada finalidade, e o controle de acesso granular acontece no robots.txt, não no llms.txt.
Dados estruturados em JSON-LD, que continuam sendo o sinal mais estabelecido e amplamente suportado — tanto por buscadores tradicionais quanto por sistemas de IA que extraem entidades e fatos de uma página.
Arquivos experimentais como agents.md e .well-known/mcp.json, sinalizando que parte da comunidade já está apostando no MCP como sucessor natural do modelo de "arquivo estático de índice".
Juntando os pontos: o Astro não tem nenhum recurso mágico dedicado exclusivamente a modelos de IA, e seria impreciso dizer que ele foi "desenhado" para essa era — a arquitetura de ilhas é anterior a esse debate por vários anos. O que ele tem é uma vantagem estrutural herdada: HTML limpo e estático por padrão é simultaneamente bom para SEO tradicional, bom para preview de redes sociais e barato de processar para qualquer sistema — humano ou agente — que precise extrair conteúdo sem custo de execução de JavaScript. Isso coloca o Astro em posição confortável para se adaptar ao que vier a seguir, seja um padrão como o llms.txt, seja algo mais próximo do MCP, sem precisar de reescrita estrutural — só de mais uma integração no build.
A cautela aqui é a mesma que orienta o resto deste artigo: nenhuma dessas ferramentas — llms.txt, Markdown paralelo, MCP — deve ser tratada como certeza definitiva. Este é, hoje, o terreno que muda mais rápido em todo o ecossistema web, e a melhor postura técnica é revisitar essa seção periodicamente, não tratá-la como resolvida.
A arquitetura de ilhas não é um recurso do Astro — é a razão de o framework existir. Toda a análise deste artigo, das vantagens de performance e SEO às limitações em aplicações densas, decorre da mesma escolha original: tratar JavaScript no cliente como exceção, não como padrão.
Isso torna o Astro excelente para o que ele foi desenhado — sites orientados a conteúdo que precisam carregar rápido e ser indexados bem — e deliberadamente menos adequado para aplicações onde a interatividade é a regra, não a exceção. A pergunta que qualquer equipe deveria fazer antes de adotar o Astro não é "esse framework é bom?", mas "o meu produto é, no fundo, conteúdo ou aplicação?". A resposta honesta a essa pergunta decide mais do que qualquer benchmark.
Um reforço final, para fechar sem deixar uma falsa impressão: a profundidade dedicada a micro frontends na Seção 4 reflete a riqueza técnica do tema, não a frequência com que ele deveria aparecer nos seus projetos. Para a esmagadora maioria dos casos, o Astro certo é o mais simples — uma aplicação, um deploy, ilhas convivendo na mesma base de código. A arquitetura distribuída é uma ferramenta para um problema organizacional específico, não um upgrade natural de maturidade.
Este bônus assume o terreno já dominado: ilhas, diretivas client:*, TypeScript e a integração React já fazem parte do seu vocabulário depois das quatro seções anteriores. Não há instalação para mostrar aqui, nem estrutura de pastas para explicar — isso está a um comando de distância na documentação oficial, e repeti-lo agora só empurraria a leitura para longe do que realmente importa. O que segue vai direto ao ponto mais avançado deste artigo em código: a diretiva server:defer consumindo um endpoint remoto, resolvendo de fato a composição assíncrona no servidor — sem boilerplate no caminho.
Um endpoint que representa "outro time" servindo conteúdo, com uma latência real simulada para deixar o comportamento assíncrono visível:
// src/pages/api/fragmento.tsexport async function GET() { const html = `<div style="padding:1rem;border:1px solid #ccc;"> Fragmento renderizado por outro serviço às ${new Date().toLocaleTimeString('pt-BR')} </div>`; return new Response(html, { headers: { 'Content-Type': 'text/html' }, });}Agora, o componente que busca e insere esse fragmento no servidor, sem bloquear o carregamento do restante da página:
---// src/components/FragmentoRemoto.astroexport const prerender = false;const resposta = await fetch(new URL('/api/fragmento', Astro.url).toString());const html = await resposta.text();---<div class="fragmento-remoto" set:html={html} />E, na página inicial, adicione a chamada com server:defer e um fallback imediato:
---// src/pages/index.astro (trecho adicionado)import FragmentoRemoto from '../components/FragmentoRemoto.astro';---<h2>Fragmento composto (estilo micro frontend)</h2><FragmentoRemoto server:defer> <div slot="fallback">Carregando fragmento do outro serviço…</div></FragmentoRemoto>Como o Astro, por padrão, faz pre-render estático, server:defer exige um servidor rodando sob demanda. Instale o adaptador Node para testar esse comportamento localmente:
npx astro add nodenpm run buildnpm run startAcesse a página novamente: por um instante você verá "Carregando fragmento do outro serviço…", e em seguida o conteúdo buscado no servidor aparece — sem que o restante da página tenha esperado por ele. É exatamente o mecanismo descrito na Seção 4.3, em miniatura.
Esse é o mecanismo real por trás da promessa de composição distribuída da Seção 4: um fragmento vindo de outra origem, renderizado no servidor, sem bloquear o restante da página e sem exigir nenhuma orquestração no cliente. O exemplo de estado compartilhado entre React e Vue via Nanostores, que fecha a fraqueza levantada na Seção 2.2, já não precisa de laboratório separado — ele mora ao lado do argumento que resolve, pronto para ser lido no calor da dúvida, não recuperado três seções depois num apêndice.
Documentação oficial do Astro — docs.astro.build/en/concepts/islands
Jason Miller, criador do Preact, sobre Islands Architecture (2020)
Discussão pública da equipe Astro sobre composição de micro frontends via múltiplos servidores — github.com/withastro/roadmap/discussions/713
Artigo técnico sobre Server Islands aplicadas a micro frontends — Talent500 Engineering Blog
Comparativo Astro vs. Next.js (2026) — kunalganglani.com
Documentação oficial do Next.js sobre Partial Prerendering — nextjs.org/docs/app/getting-started/partial-prerendering
"LLMs.txt in 2026: The Full Guide" — dados de adoção e tráfego de bots de IA (Limy, 2026)
"Astro removed its llms.txt" — relato sobre a substituição do llms.txt por servidor MCP na documentação oficial do Astro (Dachary Carey, 2026)
"Making your Astro site agent-friendly" — implementação de Markdown paralelo e negociação de conteúdo (Jimmy Guzman Moreno, 2026)
Diretório oficial de integrações do Astro — astro.build/integrations
Documentação oficial do Astro sobre compartilhamento de estado entre ilhas com Nanostores — docs.astro.build/en/recipes/sharing-state-islands
Práticas de CI/CD, contract testing e canary release para micro frontends renderizados no servidor — Habsi Tech, "Building Resilient Micro Frontends"
Relato de implementação de reverse proxy para composição de múltiplas experiências de frontend em produção — Asurion Product Development, "Not so micro-frontends: Building a Reverse Proxy"