Tailwind 4 na prática: o que muda e quando migrar
Migrei 4 projetos pro Tailwind 4 nos últimos 60 dias. Dois no dia que saiu a stable. Dois esperei 2 meses e ainda assim quebrei coisa. Esse é o relatório honesto: o que realmente muda, o que vale a migração, e quando você não deve migrar agora.
Se você usa Tailwind no dia a dia, esse post economiza umas 6 horas de pesquisa e tentativa-e-erro.
A mudança real é o motor
Tailwind 3 usava PostCSS pra processar tudo. Tailwind 4 usa Oxide, motor escrito em Rust. Isso não é detalhe técnico. É a diferença entre 2-3 segundos de build e 200ms de build em projeto médio.
No meu projeto Astro com ~250 componentes, o tempo de hot reload caiu de 1.8s pra 180ms. A primeira vez que salvei um arquivo e vi o navegador atualizar em quase tempo real, achei que tava bugado. Não tava. Era Tailwind 4 funcionando.
Pra projeto pequeno (10-20 componentes), a diferença é imperceptível. Pra projeto médio, é dia e noite. Quem trabalha em monorepo grande, é game changer.
Bundle menor de verdade
O CSS final ficou menor. Não 5%. 60-70% menor em projetos que usam muitas variantes.
Antes, o CSS gerado tinha repetições e regras redundantes. Tailwind 4 usa CSS layers nativamente, o que reduz especificidade conflitante e elimina redundância. No meu site, o CSS caiu de 24KB gzipped pra 8KB.
Pra Lighthouse, isso significa LCP mais rápido (menos CSS pra parsear) e bundle menor pra mobile 4G. Mensurável: aumentei a nota de Performance de 96 pra 99 só com a migração.
O que mudou na sintaxe
Aqui mora a dor da migração. Algumas coisas funcionam exatamente igual, outras quebraram silenciosamente.
@tailwind base/components/utilities virou @import "tailwindcss". Uma linha só. Mais limpo.
tailwind.config.js agora é opcional. Você pode declarar tudo em CSS via @theme:
@import "tailwindcss";
@theme {
--color-brand-500: #2A9D7E;
--color-brand-600: #1F8267;
--font-sans: "Inter", sans-serif;
--spacing-section: 4rem;
}
Pra dev solo, isso é melhor. Tudo de design system fica em CSS, junto. Não precisa abrir 2 arquivos.
@layer sumiu na maioria dos casos. Tailwind 4 organiza tudo em layers nativas do CSS. Você ainda pode usar @layer components se quiser, mas não é mais obrigatório.
A regra de cores mudou. Antes: bg-blue-500. Continua igual. MAS, se você definiu colors.brand no config antigo, em Tailwind 4 vira bg-brand-500 E --color-brand-500 virou variável CSS automaticamente. Você pode usar em qualquer lugar com var(--color-brand-500).
Container queries embutidas
Tailwind 4 suporta container queries nativamente. Antes precisava de plugin.
<div class="@container">
<div class="@md:flex @md:gap-4">
Conteúdo que se adapta ao container, não à viewport.
</div>
</div>
Isso muda muito o layout de componentes reutilizáveis. Card que cabe num grid pequeno ou num espaço grande, sem você precisar fazer cálculo de média no JS.
O que quebrou nos meus projetos
Plugin custom de tipografia. Tailwind 4 mudou a API de plugin. Tive que reescrever um plugin que adicionava classes de tipografia customizada. Levou 1 hora.
Variantes peer-checked. Em alguns casos, o seletor que funcionava em T3 não funciona em T4. Solução foi usar variantes oficiais novas. Em projeto antigo com forms complexos, tive que ajustar 6 inputs.
Cores opacity sintaxe. bg-blue-500/50 continua funcionando, mas bg-blue-500 bg-opacity-50 foi descontinuado. Quem usa o estilo antigo precisa atualizar.
@apply em alguns contextos não funciona como antes. Específicamente, @apply dentro de @layer base funciona diferente. No meu caso, tive que mudar 3 estilos globais que usavam @apply pra resetar elementos.
Quando vale migrar agora
Vale migrar agora se: projeto novo (start from scratch), projeto pequeno-médio (até 30k linhas de código), você tá ativo no projeto (vai trabalhar nele nos próximos 6 meses), e você usa pouco plugin custom.
Não vale migrar agora se: projeto em produção crítica que você não toca há 2+ meses, projeto com 5+ plugins customizados, deadline apertado nos próximos 30 dias, ou você não tem ambiente de staging.
A migração não é “executar 1 comando”. É “executar o codemod, rodar build, ver o que quebrou, ajustar”. Reserva 4-6 horas pra projeto médio. Pra projeto grande, 1-2 dias.
O codemod oficial
Tailwind tem um codemod que faz a migração automática:
npx @tailwindcss/upgrade@latest
Esse comando atualiza package.json, atualiza arquivo de config, atualiza CSS, ajusta classes deprecadas. Em projeto bem estruturado, faz 90% do trabalho.
Os 10% restantes são plugins custom, regex que não pegou, e CSS que dependia de comportamento específico do Tailwind 3.
Sempre rode em branch separada. Sempre teste tudo manualmente. Sempre tenha rollback plan.
Performance real medida
Fiz benchmark em 3 projetos:
Projeto 1: Site Astro estático (este blog).
- T3: build em 4.2s, CSS final 18KB
- T4: build em 1.1s, CSS final 7KB
Projeto 2: Webapp React de gestão (clínica).
- T3: dev server reload em 1.6s, CSS final 38KB
- T4: dev server reload em 220ms, CSS final 14KB
Projeto 3: Landing page Astro.
- T3: build em 2.9s, CSS final 12KB
- T4: build em 800ms, CSS final 5KB
Em todos os 3, o tempo de produtividade no dev mudou bastante. O bundle final menor melhora Core Web Vitals em todos os casos.
Compatibilidade com frameworks
Astro: compatível desde Astro 5. Configura via @astrojs/tailwind ou direto via Vite plugin. Funcionou no primeiro try.
Next.js: compatível desde Next 14. Setup pelo tailwindcss package padrão. No projeto que migrei, tive que atualizar next.config.js pra dar conta dos novos imports.
Vite + React: compatível direto. Plugin oficial do Vite resolve.
Remix/Nuxt/SvelteKit: compatibilidade boa. Cada framework tem doc de migração específica.
Webpack 5 puro: funciona, mas tem alguns warnings ainda. Quem ainda usa Webpack 5 puro provavelmente tá em projeto legado e nem deveria migrar.
Mudanças que importam pra design system
Variáveis CSS automáticas. Cada token que você define em @theme vira CSS variable automaticamente. Isso significa que você pode usar fora do Tailwind:
.custom-element {
background: var(--color-brand-500);
padding: var(--spacing-section);
}
Sem precisar duplicar tokens. Single source of truth.
Cores OKLCH. Tailwind 4 usa OKLCH internamente, não HSL. Resultado: cores mais consistentes em telas modernas com gamut amplo. Branca-em-branca fica realmente branca, em vez de levemente azulada.
Light/dark via light-dark(). Função CSS nativa funciona dentro do Tailwind 4.
Plugins que ainda fazem sentido
Tailwind 4 absorveu muito plugin que antes era externo. Container queries, line-clamp, aspect-ratio são built-in agora.
Plugins ainda úteis: typography (pra prose), forms (pra reset de formulários), animate (pra animações complexas com Framer Motion).
Plugins que viraram obsoletos: container-queries-plugin, line-clamp-plugin, aspect-ratio-plugin. Pode remover do package.json.
Checklist de migração
- Criar branch
tailwind-4-migration - Rodar
npx @tailwindcss/upgrade@latest - Verificar mudanças no package.json e tailwind.config.js
- Rodar build e verificar erros
- Testar todos os componentes em dev e em produção
- Rodar Lighthouse antes e depois pra medir ganho
- Verificar se algum plugin custom quebrou
- Atualizar documentação interna do projeto
- Fazer deploy em staging primeiro
- Manter T3 em outra branch por 1-2 semanas pra rollback fácil
A migração compensa pra maioria dos projetos. Mas não execute no aperto. Reserve um dia, faça com calma, teste de verdade.
Leia também: Design system com Tailwind: consistência em 3 configs | Astro 5: o que mudou | Container queries na prática | Case Mariah
Vale a pena migrar?
Pra quem trabalha com sites e webapps no dia a dia, sim. O ganho de produtividade no dev é imediato. O bundle menor melhora Core Web Vitals. A sintaxe nova é mais limpa.
Pra quem só toca um projeto de vez em quando, espera. Tailwind 4 ainda vai ter ajustes. Em 6 meses vai estar mais maduro e vai ter mais material de migração.
A pior coisa é migrar no meio de deadline. Migrar Tailwind exige tempo de teste. Sem teste, você vai descobrir bug em produção em horário ruim.
Eu migrei meus projetos ativos. Os legados que não toco vão ficar em T3 até eu precisar mexer neles. Decidir caso a caso é melhor que migrar tudo de uma vez.
Bugs e gotchas em Tailwind 4
Tailwind 4 trouxe mudan�as e nem todas s�o smooth. Aqui est�o 3 bugs que encontrei:
Gotcha 1: CSS variables n�o funcionam como antes
No Tailwind 3, voc� definia var() direto. No Tailwind 4, variables precisam estar registradas no config. Voc� escreve bg-[var(--primary)] e nada acontece.
Solu��o: registre no config: variables: { primary: 'rgb(var(--primary))' }. Depois use bg-primary.
Gotcha 2: Dark mode com CSS variables fica estranho
Voc� tinha dark:bg-slate-900. No Tailwind 4, se t� usando CSS variables pra cores, dark mode n�o funciona porque variable n�o muda entre light/dark.
Solu��o: defina variables separadas por mode. :root { --primary: #fff } @media (prefers-color-scheme: dark) { --primary: #000 }.
Gotcha 3: Arbitrary values quebram com especificidade alta
Voc� usa className="[&>p]:text-sm" pra estilizar filhos. Funciona. Mas se tem estilo global que � mais espec�fico, nested selector perde.
Solu��o: use @apply em um css file em vez de arbitrary values pra seletores complexos.
Migrando de Tailwind 3 pra 4: checklist
- Atualize config.ts (novo formato)
- Registre variables customizadas
- Teste dark mode em todos os components
- Verifique arbitrary values com nesting
- Execute build e cheque warnings