21/08/2026
Meu starter de Astro ganhou um update grande: o que mudou e por que ele existe
O esqueleto que uso pra começar todo site em Astro estava parado desde fevereiro. Subi ele pro Astro 7 e trouxe pra dentro tudo que já tinha virado padrão nos projetos em produção: fontes self-hosted, cabeçalhos de segurança, captura de UTM, SEO absoluto. Repositório aberto no GitHub.
Toda vez que eu começava um site novo em Astro, perdia as mesmas quatro horas. Configurar o Prettier, montar o componente de SEO, lembrar que a URL da imagem de Open Graph precisa ser absoluta senão o WhatsApp não mostra nada, copiar o _headers do projeto anterior, descobrir de novo que o pnpm 10 bloqueia o script de instalação do sharp. Nada disso é difícil. É só repetitivo o suficiente pra irritar, e sutil o suficiente pra eu errar um detalhe e só perceber depois do deploy.
Foi por isso que criei o astro-starter. Não é o starter oficial do Astro nem tenta ser: é o esqueleto do que sobrou depois de alguns sites em produção, com as decisões que eu já tinha tomado três ou quatro vezes deixando de ser decisão e virando ponto de partida.
Só que ele estava parado desde fevereiro. Enquanto isso, cinco projetos que desenvolvi (este site aqui, AS Locação, OperAqui, Missão China Health e o Toin.app) foram andando e acumulando melhorias que nunca voltavam pro template. Chegou num ponto em que o starter estava atrás dos projetos que ele deveria iniciar, o que é meio o oposto do objetivo. Semana passada sentei e fiz o caminho de volta.
O que é um starter, e o que ele não é
Um starter é um repositório que você clona pra não começar do zero. A diferença entre ele e um boilerplate genérico é o escopo: boilerplate tenta servir todo mundo e por isso não decide nada, enquanto um starter pessoal decide tudo, e é exatamente isso que economiza tempo.
Este aqui não é um tema, não tem componente de UI pronto e não tem página de exemplo pra você apagar. Ele é infraestrutura: SEO, fontes, cabeçalhos, cache, formatação, analytics e deploy já resolvidos, com o conteúdo em branco esperando o projeto. A stack é Astro 7, Tailwind CSS 4, Alpine.js 3 e Lenis, com saída estática e deploy em Cloudflare Workers.
Onde um starter desatualizado estraga a festa
O problema de um template parado não é ficar velho: é ficar enganosamente pronto. Você clona confiando que está começando com a base atual, e na verdade começa seis meses atrás. Pior: as correções que você fez nos projetos reais nesse meio-tempo não estão ali, então você repete os mesmos bugs que já tinha resolvido.
No meu caso, o starter tinha um tailwind.config.mjs que o Tailwind 4 não usa mais (a configuração migrou pro CSS, via @theme), carregava fonte por <link> pro fonts.googleapis.com, e o Seo.astro montava a URL da imagem de Open Graph em caminho relativo. Esse último é o tipo de coisa que passa despercebida: o site funciona, o Lighthouse não reclama, e só quem manda o link no WhatsApp descobre que o card vem sem imagem, porque o WhatsApp e o Facebook não resolvem caminho relativo.
O que mudou nesse update
| Área | Antes | Agora |
|---|---|---|
| Astro | 5.16 | 7.2.4 |
| Tailwind | 4 com tailwind.config.mjs | 4.3.3, configurado por CSS no @theme |
| Alpine | @astrojs/alpinejs 0.4 | 1.0 |
| Fontes | <link> pro Google Fonts | astro:fonts, self-hosted no build |
| Segurança | nada | _headers com HSTS, nosniff, X-Frame-Options |
| SEO | canonical e OG relativas | absolutas, tipadas |
| Analytics | GA4 solto | Analytics.astro com captura de UTM |
| Node | não declarado | engines >=22.12 e .nvmrc |
Abaixo, o que está por trás de cada linha que merece explicação.
Fontes self-hosted via astro:fonts
Essa é a que mais muda o resultado percebido. Em vez do <link> pro fonts.googleapis.com, o Astro baixa os arquivos no build, gera o @font-face com métricas de fallback e emite o preload sozinho.
Duas vantagens concretas: um round-trip a menos em outro domínio antes de conseguir pintar o texto, e o fim do pulo de layout na troca da fonte de sistema pela real, que as métricas de fallback resolvem. Já tinha escrito sobre self-host de fontes com Fontsource quando fiz isso neste site; a diferença é que agora o astro:fonts faz o trabalho nativamente, sem dependência extra.
Um detalhe que custa banda se passar batido: declarar sempre styles: ['normal']. Sem isso, fontes como o Inter trazem as variantes itálicas com o mesmo unicode-range, e o navegador baixa as duas famílias.
public/_headers com o raciocínio junto
Esse veio quase inteiro do toin-website. Traz HSTS, Referrer-Policy, X-Content-Type-Options, X-Frame-Options, Permissions-Policy e immutable no /_astro/*.
O que eu acho que faz diferença aqui não são os cabeçalhos em si, que são padrão de mercado: é que cada bloco explica por que está ali, incluindo a ausência deliberada de CSP, que é uma decisão consciente e não um esquecimento. E documenta as duas armadilhas do formato: a indentação dos cabeçalhos é obrigatória (sem ela a linha vira um padrão de rota e o header some sem erro nenhum), e /* não cobre o que já está em cache.
No caso do HSTS tem um aviso explícito sobre o token preload, que só torna o domínio elegível à lista embutida nos navegadores. Uma vez aceito, sair leva meses, e nesse meio-tempo qualquer subdomínio que só saiba HTTP fica inacessível.
Captura de origem no Analytics.astro
Esse resolve um problema que aparece em todo projeto de cliente. O componente captura UTMs e click-ids na primeira página da visita, guarda na sessão e injeta como campos ocultos em todo <form> da página. O lead chega no destino sabendo de onde veio.
A captura precisa acontecer na entrada porque a pessoa quase sempre navega antes de preencher o formulário: sem o sessionStorage, os parâmetros se perderiam no primeiro clique. O GA4 só sobe se analytics.ga4 estiver preenchido no site.json, então o starter não fica disparando script de rastreamento em projeto que ainda nem tem conta.
SEO absoluto e robots.txt gerado no build
O Seo.astro foi tipado e agora resolve og:image e canonical em absoluto. O robots.txt passou a ser gerado no build a partir do site do config, em vez de ser um arquivo estático em public/, que num template aponta pro domínio errado no primeiro clone e ninguém percebe.
O sitemap ganhou um filtro EXCLUDED: página marcada com noindex fica fora do sitemap, porque sinalizar as duas coisas ao mesmo tempo é contraditório pros buscadores.
O resto
Coisas menores que somam: .gitattributes normalizando para LF (senão o Windows e o Prettier brigam a cada pnpm format), .nvmrc, pnpm-workspace.yaml liberando os scripts de instalação do sharp, esbuild e workerd que o pnpm 10+ bloqueia por padrão, página 404.astro, env.d.ts, um anchor-scroll.ts que desconta o header fixo, e wrangler.jsonc descrevendo o Worker de Static Assets.
O README foi reescrito inteiro em português, com checklist de projeto novo e uma seção de decisões não-óbvias. O CLAUDE.md descreve o repositório como esqueleto, pra quem usa Claude Code não sair inventando estrutura que já existe.
Decisões que documentei de propósito
Tem um bloco no README que eu gosto mais do que o código: as decisões que parecem erro pra quem chega. Um starter sem elas vira um lugar onde as pessoas "consertam" coisas que estavam certas.
- Não existe
tailwind.config.mjs, e não deve existir. O Tailwind 4 configura por CSS. Os tokens vivem no@themedoglobal.css. trailingSlash: 'always'. O que importa é escolher um e manter. Já escrevi sobre o 308 do Cloudflare e as combinações de trailing slash no Astro; o starter usaalwaysporque é o default seguro, mas a escolha está documentada como escolha.scroll-behavior: smoothestá fora do CSS de propósito. O Lenis já anima a rolagem e oanchor-scroll.tsdesconta o header. Ligar os dois faz a rolagem brigar consigo mesma.- Comentários longos no markup usam
{/* */}, nunca<!-- -->. Os primeiros o Astro remove no build, os segundos vão parar no HTML do visitante.
Como usar
git clone https://github.com/toledox82/astro-starter.git meu-projeto cd meu-projeto pnpm install pnpm dev
Depois disso, o checklist do README tem oito itens: nome no package.json e no wrangler.jsonc, SITE no astro.config.mjs, src/data/site.json, paleta no global.css, as fontes, os favicons, a imagem de OG e o compatibility_date.
Requer Node 22.12 ou superior e pnpm. O pnpm não é preferência minha aqui, é requisito: o pnpm-workspace.yaml é o que libera os scripts de instalação bloqueados por padrão.
Resumo
O que fazer: clonar, rodar o checklist de oito itens do README, e confiar que SEO, fontes, cabeçalhos e formatação já estão resolvidos.
O que não fazer: recriar o tailwind.config.mjs, ligar scroll-behavior: smooth, marcar uma página como noindex sem acrescentar o caminho ao EXCLUDED, ou trocar as URLs absolutas do Open Graph por relativas.
O que mudou nesse update: Astro 5.16 pro 7.2.4, fontes self-hosted, cabeçalhos de segurança documentados, captura de UTM, SEO absoluto e uma camada de infraestrutura que veio dos projetos em produção de volta pro template.
Testa e me conta
O repositório está aberto: github.com/toledox82/astro-starter
Se você trabalha com Astro, clona e usa no próximo projeto. E se topar contribuir, é bem-vindo de verdade:
- Achou um bug ou um detalhe desatualizado? Abre uma issue. O update deste mês nasceu de coisas que eu mesmo fui anotando ao longo dos projetos, então a lista de melhorias sempre tem espaço.
- Discorda de alguma decisão? Melhor ainda. As decisões do README são as que fizeram sentido pra mim; se você tem um argumento melhor pra alguma delas, quero ouvir.
- Tem algo que sempre repete nos seus projetos e não está ali? Manda. É exatamente assim que esse repositório cresce.
- Se ele te poupar uma tarde, deixa uma estrela no GitHub. ⭐ É o que me diz que vale a pena continuar mantendo o repositório público e atualizado.
E se o starter ou este post te ajudaram de alguma forma, seja economizando algumas horas de setup ou passando um detalhe que você não conhecia, você pode retribuir me pagando um café ☕. Não é obrigatório e nada aqui fica atrás de paywall: manter o repositório aberto e escrever sobre ele é uma escolha minha. Mas ajuda, e é o que sustenta o tempo que vai nisso. No rodapé do site tem outras formas de colaborar sem gastar nada, como usar meus links de indicação ao abrir conta em serviços que você já ia contratar de qualquer jeito.