React Server Components chegaram com promessas grandes, e com uma confusão proporcional. Depois de meses usando RSC em produção com Next.js App Router, a pergunta mais comum que recebo ainda é: "Mas quando eu uso Server Component mesmo?"
Este artigo não é introdução, assume que você já sabe o que é RSC. É um guia de decisão prático: quando usar o quê, por que, e os erros que quase todo mundo comete na transição.
O modelo mental correto
O erro mais comum é pensar em RSC como "componentes que rodam no servidor" e Client Components como "componentes que rodam no cliente". Essa descrição está correta mas incompleta de uma forma que gera más decisões.
A forma mais útil de pensar:
- Server Components são funções que rodam apenas no servidor, têm acesso direto a dados, banco, filesystem, APIs internas, e nunca são incluídas no bundle do cliente. Elas produzem HTML + RSC payload que é enviado ao cliente.
- Client Components são funções que rodam no cliente, e também no servidor para hidratação. Têm acesso a state, effects, event handlers, e APIs do browser. São incluídas no bundle.
A implicação prática: Server Components não carregam JavaScript no cliente. Qualquer lógica, dependência, ou processamento feito num Server Component tem custo zero de bundle.
Quando usar Server Components
Use Server Components quando o componente:
- Busca dados diretamente, banco, API, filesystem
- Usa dependências grandes que não precisam ser interativas (
marked,sharp, parsers pesados) - Renderiza conteúdo estático ou com dados que vêm do servidor
- Precisa de acesso a variáveis de ambiente secretas
- É uma camada de composição que não tem estado ou interatividade própria
// Server Component: busca direta, sem bundle no cliente
async function ProductPage({ id }: { id: string }) {
const product = await db.product.findUnique({ where: { id } })
return (
<div>
<h1>{product.name}</h1>
<ProductActions product={product} /> {/* Client Component */}
</div>
)
}
Quando usar Client Components
Use Client Components quando o componente precisa de:
- Estado local (
useState,useReducer) - Efeitos (
useEffect,useLayoutEffect) - Event handlers (
onClick,onChange, etc.) - APIs do browser (
localStorage,window,navigator) - Bibliotecas que dependem de APIs do browser
'use client'
import { useState } from 'react'
function ProductActions({ product }: { product: Product }) {
const [quantity, setQuantity] = useState(1)
return (
<div>
<input
type="number"
value={quantity}
onChange={e => setQuantity(Number(e.target.value))}
/>
<button onClick={() => addToCart(product.id, quantity)}>
Adicionar ao carrinho
</button>
</div>
)
}
Os erros mais comuns
1. Marcar tudo como 'use client' por precaução
O erro mais comum na transição. Se você adiciona 'use client' em todos os componentes "só para funcionar", você perdeu o benefício central dos RSC, redução de bundle. Um Server Component importado dentro de um Client Component se torna um Client Component também.
2. Passar objetos não-serializáveis para Client Components
Server Components podem passar props para Client Components, mas apenas props serializáveis, strings, números, arrays, objetos simples. Funções, instâncias de classe, e objetos com métodos não podem ser passados. Isso pega muita gente de surpresa.
// ❌ Erro: funções não podem ser passadas de Server para Client
<ClientComponent handler={someServerFunction} />
// ✅ Correto: defina o handler no próprio Client Component
// ou use Server Actions para callbacks
3. Confundir Server Actions com Server Components
Server Actions são funções assíncronas que rodam no servidor e podem ser chamadas de Client Components. Elas são o mecanismo para mutações, não para busca de dados. Use Server Components para leitura, Server Actions para escrita.
4. Waterfall de dados não intencional
Com async/await em Server Components, é fácil criar waterfalls:
// ❌ Waterfall: espera um, depois o outro
const user = await fetchUser(id)
const orders = await fetchOrders(user.id)
// ✅ Paralelo: busca simultânea
const [user, orders] = await Promise.all([
fetchUser(id),
fetchOrders(id)
])
O padrão de composição que funciona
O padrão mais eficiente é manter o máximo possível como Server Components, e empurrar Client Components para as folhas da árvore, os componentes mais próximos da interatividade real.
Uma página típica bem estruturada com RSC tem: Server Component como raiz, busca dados, composição, Client Components só onde há interatividade, e Server Components aninhados para sub-seções que precisam de dados mas não de interatividade.
Quando você interioriza esse padrão, a arquitetura começa a fluir, e o bundle do cliente encolhe.
Curtiu o conteúdo?
Construo produtos web e soluções com IA do jeito certo — arquitetura sólida, código sustentável e entrega real.
Vamos conversar