Disponível para freelancerEntre em contato para que eu possa ajudar seu negócio a crescer ou tirar sua ideia do papel!

Estou interessado
Estrutura de Pastas no Frontend Que Escala

Estrutura de Pastas no Frontend Que Escala

Todo projeto começa limpo. Seis meses depois, components/ tem 80 arquivos, ninguém sabe onde fica nada, e o onboarding leva uma semana.

A estrutura de pastas não é o problema. A ausência de regras é.


As Duas Abordagens Comuns

Por tipo (comum no início)

components/
  Button.tsx
  Modal.tsx
  ProductCard.tsx
  UserProfile.tsx
hooks/
  useCart.ts
  useAuth.ts
  useProducts.ts
utils/
  formatDate.ts
  formatPrice.ts

Parece organizado. Mas conforme o projeto cresce, components/ vira um depósito. Nada é agrupado pelo que pertence junto.


Por funcionalidade (o que realmente escala)

features/
  cart/
    components/
    hooks/
    utils/
    index.ts
  auth/
    components/
    hooks/
    utils/
    index.ts
  products/
    components/
    hooks/
    utils/
    index.ts

Cada funcionalidade é dona do seu código. Você consegue ler, alterar ou deletar uma feature sem precisar vasculhar o repositório inteiro.


Uma Estrutura Prática para Next.js App Router

app/
  [locale]/
    (marketing)/
      page.tsx
    (app)/
      dashboard/
        page.tsx
      settings/
        page.tsx
    layout.tsx

components/
  ui/           # genéricos, reutilizáveis (Button, Input, Modal)
  layout/       # estruturais (Header, Footer, Sidebar)

features/
  auth/
    components/
      LoginForm.tsx
      AuthGuard.tsx
    hooks/
      useAuth.ts
    actions/
      login.ts
    index.ts
  cart/
    components/
      CartDrawer.tsx
      CartItem.tsx
    hooks/
      useCart.ts
    store/
      cart.store.ts
    index.ts

lib/
  db.ts
  flags.ts
  analytics.ts

hooks/           # apenas hooks verdadeiramente globais
utils/           # apenas utilitários verdadeiramente globais
types/           # tipos TypeScript compartilhados

O Princípio da Colocalização

Mantenha o código perto de onde ele é usado.

Se um hook só é usado dentro de CartDrawer.tsx, ele não pertence a /hooks. Ele pertence ao lado do componente.

features/cart/
  components/
    CartDrawer.tsx
    CartDrawer.hooks.ts    # usado só aqui
  hooks/
    useCart.ts             # usado em toda a feature de cart

Suba na árvore de pastas apenas quando algo é compartilhado entre features. Não mova arquivos "só por precaução".


O Padrão de Barrel com index.ts

Use index.ts para definir o que uma feature expõe publicamente.

// features/cart/index.ts
export { CartDrawer } from './components/CartDrawer'
export { useCart } from './hooks/useCart'
export type { CartItem } from './types'

Depois importe de forma limpa de outras features:

import { CartDrawer, useCart } from '@/features/cart'

Essa é a API pública da sua feature. Arquivos internos ficam internos.


Quando Barrel Files Dão Errado

Barrel files melhoram os imports — mas têm um custo.

// ❌ Todo arquivo do app é incluído no bundle quando isso é importado
export * from './Button'
export * from './Modal'
export * from './ProductCard'
// ...50 exports a mais

O tree-shaking falha com barrels grandes — e o seu bundle paga o preço.

Regra: Use barrel files no nível de feature (não em components/ui/). Mantenha barrels de UI pequenos e explícitos.


Route Groups no Next.js App Router

Use route groups (nome-do-grupo) para separar responsabilidades sem afetar a URL.

app/
  [locale]/
    (marketing)/
      page.tsx          → /pt
      about/
        page.tsx        → /pt/about
    (app)/
      layout.tsx        → layout autenticado compartilhado
      dashboard/
        page.tsx        → /pt/dashboard
      settings/
        page.tsx        → /pt/settings

Páginas de marketing e páginas do app compartilham o parâmetro de locale mas têm layouts diferentes. Route groups os separam de forma limpa.


Erros Comuns

1. Uma pasta components/ gigante

components/
  LoginButton.tsx
  ProductCard.tsx
  CartItem.tsx
  DashboardHeader.tsx
  AdminTable.tsx
  ... 70 arquivos a mais

Sem agrupamento = sem estrutura. Extraia para features.


2. hooks/ global para hooks específicos de uma feature

// ❌ hooks/useCartDiscount.ts — usado só no cart
// ✅ features/cart/hooks/useCartDiscount.ts

3. Aninhamento profundo demais

features/
  checkout/
    components/
      steps/
        payment/
          forms/
            fields/
              CreditCardField.tsx

Além de 4 níveis, a navegação fica dolorosa. Achate quando o aninhamento não adiciona significado.


4. Importar diretamente entre features

// ❌ Acopla features diretamente
import { CartItem } from '../cart/components/CartItem'
// ✅ Importe pela API pública
import { CartItem } from '@/features/cart'

Isso torna seguro refatorar uma feature sem quebrar outras.


Quando Refatorar a Estrutura

SinalAção
"Onde esse arquivo fica?" — todo mundo perguntaClarifique as regras, documente
Arquivos de uma feature espalhados em 3+ pastasAgrupe por feature
Deletar uma feature exige busca no repositório inteiroReorganize por feature
Novos devs levam >1 hora para encontrar coisasMuito aninhamento ou sem convenções

O Que Fazer Agora

  • Audite sua estrutura atual: conte arquivos por pasta, identifique os depósitos
  • Escolha uma feature e mova-a para features/sua-feature/
  • Adicione um index.ts para definir a API pública dela
  • Escreva as regras — até um README de 5 linhas em /features ajuda no onboarding

Estrutura não é sobre perfeição. É sobre tornar a próxima decisão óbvia.

Quando um novo arquivo chega, a pasta certa deve ser clara sem precisar de uma discussão em equipe. Esse é o objetivo.