Qual é a Estrutura de Diretórios Padrão de um Projeto Next.js?
Uma estrutura de diretórios padrão de um projeto Next.js não é uma única árvore de pastas correta que se aplica de forma idêntica a todas as equipes. Em vez disso, ela significa seguir convenções definidas para os arquivos de roteamento que o framework precisa interpretar, enquanto o restante do código é colocado de acordo com a natureza do projeto. Para um novo projeto, uma abordagem fácil de entender costuma ser usar src/app como centro das URLs e dos pontos de entrada das páginas, separar em components a UI usada em vários lugares, colocar a lógica específica de funcionalidades em features quando necessário e manter utilitários compartilhados em lib. O App Router é a principal abordagem de roteamento no Next.js atual, enquanto o Pages Router continua com suporte. nextjs.orgnextjs.org
Ao definir uma estrutura pela primeira vez, o importante não é criar o maior número possível de pastas. Primeiro, diferencie quais arquivos criam URLs, quais tratam layouts, telas de erro e APIs e qual código é usado apenas em uma tela específica. Este artigo examina uma estrutura sustentável centrada no App Router com base nessas distinções.
Por que não existe uma “única estrutura padrão” no Next.js?
O Next.js fornece convenções para criar rotas a partir de arquivos e pastas, mas não determina exatamente quais pastas devem conter cada componente e cada parte da lógica de negócio. No App Router, em particular, as pastas representam segmentos de URL, e arquivos especiais como page.tsx e route.ts criam pontos de entrada públicos reais. Em contraste, arquivos comuns colocados dentro de uma rota não se tornam rotas externas por padrão. nextjs.org
Por causa dessa característica, as estruturas podem variar até mesmo entre aplicações Next.js. Um pequeno site de marketing pode precisar apenas de app e de alguns componentes compartilhados. Já em um serviço com vários domínios, como dashboards, pedidos e contas, separar código específico de funcionalidades do código compartilhado facilita compreender o escopo das mudanças. Essa não é uma regra absoluta exigida pelo Next.js, mas uma abordagem de organização de código que a equipe escolhe adotar sobre as convenções de roteamento.
Portanto, é menos confuso pensar em “padrão” nas duas camadas a seguir.
| Categoria | Natureza | Exemplos típicos |
|---|---|---|
| Convenções interpretadas pelo Next.js | Os nomes e locais dos arquivos afetam diretamente o comportamento | app/page.tsx, app/layout.tsx, app/api/users/route.ts |
| Convenções definidas pelo projeto | A equipe define nomes e limites para seus próprios fins | components, features, lib, hooks, types |
Alterar arbitrariamente a primeira camada pode modificar o roteamento ou o comportamento de UIs especiais. A segunda camada pode ser omitida ou combinada conforme a escala e a complexidade do domínio. Por exemplo, uma estrutura sem features é possível, e não há necessidade de segmentar excessivamente cada parte do código em um projeto pequeno.
Por que novos projetos devem ser projetados em torno do App Router?
O App Router é uma abordagem para criar páginas e layouts com base no diretório app. A documentação oficial recomenda migrar do Pages Router para o App Router para aproveitar os recursos mais recentes do React, enquanto o próprio Pages Router permanece com suporte. Portanto, você deve entender as convenções de pages ao manter ou aprender a estrutura de um projeto existente, mas é natural tratar o App Router como candidato padrão ao projetar uma nova estrutura. nextjs.org
O ponto-chave do App Router é conectar a hierarquia de URLs à hierarquia de arquivos. Por exemplo, app/dashboard/page.tsx torna-se o ponto de entrada da página /dashboard, enquanto app/dashboard/layout.tsx, abaixo dele, pode fornecer um layout aplicado às subrotas do dashboard. O app/layout.tsx raiz é o layout raiz que envolve todas as rotas. nextjs.org
Essa abordagem é adequada para manter por perto o código do nível da tela. Abas, tabelas e UI de filtros necessárias apenas para /dashboard podem ficar em app/dashboard, enquanto botões ou campos de entrada reutilizados em várias telas podem ser movidos para uma pasta compartilhada externa. O principal critério não é “qual tecnologia foi usada para escrever este arquivo”, mas “em qual escopo ele é reutilizado?”.
No entanto, usar o App Router não significa que todo o código deve ficar dentro de app. Você pode tratar app como um limite que torna as URLs e os arquivos especiais fáceis de ler e separar o código compartilhado ou implementações complexas de funcionalidades em outras pastas, conforme necessário. Essa separação não é feita automaticamente pelo Next.js; ela é uma convenção estrutural que a equipe define de forma consistente.
Quando você deve usar uma pasta src e o que permanece na raiz?
src é opcional. Quando você a usa, pode reunir app e o código-fonte da aplicação dentro de src, separando visualmente os arquivos de configuração do código executado em tempo de execução. Em contraste, public, package.json, next.config.js, tsconfig.json e arquivos .env.* pertencem à raiz do projeto. nextjs.org
O exemplo a seguir é uma estrutura fácil de entender ao usar o App Router junto com src.
my-app/
├─ public/
│ ├─ images/
│ └─ fonts/
├─ src/
│ ├─ app/
│ │ ├─ layout.tsx
│ │ ├─ page.tsx
│ │ ├─ globals.css
│ │ ├─ (marketing)/
│ │ │ └─ about/
│ │ │ └─ page.tsx
│ │ ├─ dashboard/
│ │ │ ├─ layout.tsx
│ │ │ ├─ page.tsx
│ │ │ ├─ loading.tsx
│ │ │ ├─ error.tsx
│ │ │ └─ _components/
│ │ └─ api/
│ │ └─ users/
│ │ └─ route.ts
│ ├─ components/
│ ├─ features/
│ ├─ lib/
│ ├─ hooks/
│ └─ types/
├─ .env.local
├─ next.config.js
├─ package.json
└─ tsconfig.json
Neste exemplo, src é apenas um limite para o código da aplicação, e não um mecanismo obrigatório que altera o comportamento. Se um projeto existente já possui app na raiz, seguir a convenção estabelecida de forma consistente pode ser melhor do que forçar a inclusão de src. Em particular, se diretórios chamados app ou pages existirem tanto na raiz quanto em src, o diretório da raiz terá precedência; por isso, é importante não manter estruturas duplicadas por um período prolongado durante uma migração. nextjs.org
O critério prático para escolher src é simples. Ele é útil se você quiser separar claramente os arquivos de configuração do código do produto ou esperar que o número de arquivos-fonte cresça. Por outro lado, não há necessidade de adotá-lo em um projeto de aprendizado ou em um projeto muito pequeno cuja estrutura da raiz já seja clara.
Quais arquivos na pasta app criam rotas reais?
No App Router, as pastas representam partes de uma URL, ou segmentos. No entanto, criar apenas uma pasta app/dashboard não transforma /dashboard em uma página pública. Se essa pasta contiver page.tsx, ela se tornará uma rota que fornece UI de página; se contiver route.ts, ela se tornará um endpoint de API baseado em um Route Handler. nextjs.org
Por exemplo, considere a estrutura a seguir.
src/app/
├─ page.tsx
├─ about/
│ └─ page.tsx
├─ dashboard/
│ ├─ page.tsx
│ └─ reports/
│ └─ page.tsx
└─ api/
└─ users/
└─ route.ts
Nesse caso, page.tsx corresponde a /, /about, /dashboard e /dashboard/reports, respectivamente. api/users/route.ts não é uma página de UI; ele define um endpoint de API. Depois de entender que page.tsx e route.ts funcionam como os pontos de entrada públicos de uma rota, fica claro por que outros arquivos podem estar na mesma pasta. nextjs.org
Essa propriedade pode ser vista como colocation. Colocation é uma abordagem organizacional que mantém códigos relacionados próximos uns dos outros. Por exemplo, componentes de tabela usados apenas em dashboard, funções de formatação específicas da tela e código de transformação de dados de teste podem ser colocados perto de app/dashboard. Isso não significa que pastas compartilhadas nunca devam ser usadas. Basta mover o código reutilizado por outras rotas para pastas com escopo mais amplo.
Como os arquivos layout, loading e error devem ser separados?
layout.tsx trata a estrutura de UI compartilhada. O app/layout.tsx raiz envolve todas as rotas, enquanto um layout.tsx em uma pasta filha é aplicado de forma aninhada às suas subrotas. Por exemplo, se a navegação do dashboard for compartilhada por /dashboard e /dashboard/reports, ela poderá ficar em app/dashboard/layout.tsx. nextjs.org
page.tsx é a UI da página exibida em um caminho específico. Se um layout é a estrutura externa repetida, uma página está mais próxima do conteúdo específico do caminho que muda dentro dela. Separá-los significa que você não precisa repetir a navegação ou os quadros compartilhados em todas as páginas.
O App Router também fornece arquivos reservados para UI específica de estado. loading.tsx é usado para UI de carregamento, error.tsx para UI de erro e not-found.tsx para UI de não encontrado. Diferentemente de arquivos de componentes comuns, o Next.js interpreta esses arquivos para funções específicas; portanto, eles devem ser posicionados considerando sua função e escopo. nextjs.org
Por exemplo, se você quiser mostrar uma tela separada enquanto os dados são preparados em /dashboard, pode considerar app/dashboard/loading.tsx; se precisar de uma tela para tratar erros nesse escopo, pode considerar app/dashboard/error.tsx. Não é necessário adicionar esses arquivos mecanicamente a todas as pastas. Decidir com base em cada rota realmente precisar ou não de UI separada para estados de espera, erro ou não encontrado mantém a estrutura concisa.
Como as rotas dinâmicas e as rotas de API são representadas nos nomes das pastas?
Use a notação com colchetes quando parte de uma rota não for predeterminada. [slug] significa um segmento dinâmico, [...slug] significa todos os subsegmentos seguintes e [[...slug]] significa uma forma opcional em que esses subsegmentos podem estar ausentes. nextjs.org
Por exemplo, uma página cujo identificador de post varia pode ser estruturada da seguinte forma.
src/app/posts/
└─ [slug]/
└─ page.tsx
Nessa estrutura, [slug] não é um nome de pasta fixo; é um placeholder que recebe a parte variável da URL. Em contraste, quando vários níveis de uma rota precisam ser tratados por uma única convenção, considere [...slug] ou [[...slug]]. A notação a escolher depende de ao menos um subcaminho precisar existir e de o caso sem caminho também precisar ser tratado pela mesma tela. nextjs.org
Ao criar APIs, route.ts é o ponto de entrada de um Route Handler. Portanto, você pode representar a estrutura de URL com pastas como app/api/users/route.ts e colocar route.ts no final. Tanto para páginas quanto para APIs, ler a hierarquia de pastas permite inferir o caminho aproximado. Porém, é melhor separar adequadamente os arquivos de implementação dedicados para que a UI e o código de processamento no servidor não fiquem excessivamente misturados e extensos na mesma área. nextjs.org
Por que grupos de rotas e pastas privadas são necessários?
Uma pasta envolvida por parênteses, como (marketing), é um grupo de rotas. Trata-se de um agrupamento lógico que não é incluído na URL. Por exemplo, você pode agrupar páginas voltadas a marketing, como informações da empresa e preços, enquanto gerencia as telas de uso do produto em uma estrutura separada. app/(marketing)/about/page.tsx torna-se a rota /about sem o nome do grupo. nextjs.org
Grupos de rotas são úteis quando você quer mostrar limites de layout ou propriedade de código sem alterar a URL. No entanto, como o nome do grupo não aparece na URL, ocorre um conflito se grupos separados acabarem criando a mesma URL. Além disso, uma configuração que transita entre vários layouts raiz pode causar um carregamento completo da página; portanto, dividir layouts raiz não deve ser feito sem critério apenas para deixar as pastas mais organizadas visualmente. nextjs.org
Pastas que começam com sublinhado, como _components e _lib, são pastas privadas e são excluídas do roteamento. No App Router, arquivos comuns não se tornam rotas por padrão, então um sublinhado não é estritamente necessário. Ainda assim, ele pode ser útil quando você quer marcar visivelmente o limite entre os arquivos especiais de roteamento e a implementação interna, ou evitar confusão com nomes de arquivos reservados. nextjs.org
Por exemplo, app/dashboard/_components/summary-card.tsx comunica que se trata de uma UI específica do dashboard. No entanto, se esse componente começar a ser usado repetidamente em outras funcionalidades, será mais natural considerar movê-lo da pasta com sublinhado para components compartilhado ou para um limite de funcionalidade adequado. Lembre-se de que um prefixo de pasta não é um mecanismo de controle de acesso; ele é uma notação que comunica o papel do código.
Como distinguir components, features, lib, hooks e types?
Essas pastas são escolhas organizacionais opcionais, não convenções reservadas do App Router. Portanto, os limites de responsabilidade acordados pela equipe importam mais do que os próprios nomes. As distinções a seguir são um ponto de partida comum.
| Pasta | Código normalmente colocado nela | Critério de posicionamento |
|---|---|---|
components | UI reutilizada em várias telas | Não está vinculado a uma URL ou domínio específico? |
features | Implementação no nível de funcionalidade ou domínio | Há um conceito de negócio claro, como contas, pedidos ou dashboards? |
lib | Utilitários e clientes compartilhados | É uma ferramenta compartilhada em vez de UI? |
hooks | Hooks reutilizáveis | Vários componentes compartilham o mesmo estado ou comportamento? |
types | Tipos compartilhados | Várias áreas fazem referência às mesmas definições de tipo? |
components pode conter não apenas botões genéricos, mas também UI composta compartilhada entre várias funcionalidades. No entanto, transformar todo elemento de UI em um componente compartilhado globalmente desde o início pode abstrair implementações que, na verdade, são necessárias apenas em uma tela. Outra abordagem é mantê-lo inicialmente perto da rota e movê-lo apenas quando for usado de maneira estável em dois ou mais lugares e tiver uma interface compartilhada clara.
features é especialmente fácil de ler quando é necessária uma estrutura centrada no domínio. Por exemplo, se pedidos e contas tiverem, cada um, telas, UI e código de processamento de dados independentes, você pode agrupá-los como features/orders e features/account. Por outro lado, criar pastas de funcionalidades demais em um site simples pode obrigar as pessoas a percorrer muitas pastas apenas para encontrar arquivos. É melhor introduzi-las somente quando os limites das funcionalidades corresponderem a conceitos reais do produto.
lib é uma possível localização para código de base sem UI, como utilitários compartilhados ou clientes de servidor. No entanto, se todo arquivo de função se acumular em lib, ela poderá se tornar uma grande área de armazenamento difícil de entender. Uma regra prática é manter as ferramentas usadas apenas por uma funcionalidade perto dessa funcionalidade ou rota e mover para lib apenas o código compartilhado em vários lugares.
Por que public e os arquivos de variáveis de ambiente ficam na raiz do projeto?
public é a pasta na raiz do projeto destinada a arquivos estáticos. Os arquivos colocados nela são servidos a partir do caminho raiz; por exemplo, public/profile.png é referenciado como /profile.png. Isso fornece um único lugar para arquivos servidos estaticamente, como imagens e fontes. nextjs.org
Mesmo ao usar src, você não deve pensar na estrutura como uma transferência de public para src/public. public permanece na raiz do projeto, e package.json, next.config.js, tsconfig.json e .env.* também são gerenciados a partir da raiz. Em particular, como arquivos locais de variáveis de ambiente, como .env.local, podem conter segredos, é importante estabelecer uma regra operacional para não incluí-los no controle de versão. nextjs.org
Distinguir as funções dos recursos estáticos e do código-fonte da aplicação torna os caminhos mais fáceis de interpretar. Os arquivos em src/app são código que cria telas ou roteamento, enquanto os arquivos em public são recursos estáticos referenciados por URL. Mesmo quando a mesma imagem é usada em uma tela, é preciso entender de forma diferente seu método de entrega e caminho de referência conforme o local onde o arquivo é colocado.
Como isso difere da estrutura do Pages Router?
O Pages Router funciona tratando os arquivos no diretório pages como rotas. Por exemplo, pages/index.tsx corresponde a /, e pages/about.tsx corresponde a /about. As convenções de arquivos reservados também atribuem funções especiais a _app, _document, 404, 500 e outros. nextjs.org
É fácil cometer erros se você enxergar o App Router e o Pages Router como abordagens que diferem apenas no nome da pasta. No App Router, arquivos especiais como page.tsx, layout.tsx e route.ts sob segmentos de pasta dividem responsabilidades, enquanto arquivos comuns não são rotas por padrão. No Pages Router, os arquivos dentro de pages estão conectados mais diretamente às rotas. nextjs.orgnextjs.org
Ao trabalhar em um projeto existente com Pages Router, você deve respeitar suas convenções atuais baseadas em pages. Por outro lado, ao iniciar um novo projeto, basear a estrutura em um exemplo centrado no App Router e adicionar pastas organizacionais apenas quando realmente necessário reduz a sobrecarga. É importante não confundir as convenções dos dois roteadores dentro do mesmo desenho de diretórios.
Quais critérios você deve usar para escolher uma estrutura em um projeto real?
Primeiro, comece pela estrutura de URLs. Liste os caminhos principais que os usuários acessarão e, em seguida, determine quais layouts compartilhados cada caminho usa. Represente o resultado por meio das pastas em app e do posicionamento de page.tsx e layout.tsx. Use grupos de rotas quando houver um motivo claro para dividir áreas de tela ou layouts sem alterar URLs. nextjs.orgnextjs.org
Segundo, avalie o escopo de reutilização. Mantenha perto da rota o código usado por apenas uma rota. A UI usada por várias rotas pode ser movida para um escopo mais amplo, como components, e os utilitários usados por várias funcionalidades podem ser movidos para lib. Em vez de generalizar tudo desde o início, separar o código quando surgirem padrões reais de reutilização e mudança ajuda a reduzir abstrações desnecessárias.
Terceiro, considere a independência das funcionalidades. Se funcionalidades com áreas de responsabilidade e terminologia claras — como contas, administração ou pedidos — ficarem maiores, limites de domínio como features podem ser úteis. Por outro lado, quando há poucas telas e as distinções entre funcionalidades são fracas, colocation em app junto com um pequeno número de pastas compartilhadas pode ser suficiente.
Quarto, verifique o custo de descoberta da equipe. Quando uma nova pessoa na equipe procura o código de uma URL específica, ela deve conseguir seguir o caminho em app e encontrar a página e a implementação dedicada. Os nomes e locais dos botões ou utilitários compartilhados também devem ser previsíveis. Uma boa estrutura vem mais dessa previsibilidade do que de nomes de pastas da moda.
Quais equívocos e armadilhas estruturais você deve evitar?
O primeiro equívoco é que “criar uma pasta cria imediatamente uma URL”. No App Router, uma pasta representa um segmento, mas precisa de page.tsx ou route.ts para se tornar uma página pública ou endpoint de API. Essa regra permite que arquivos internos relacionados fiquem juntos na pasta da rota. nextjs.org
O segundo equívoco é que “sem uma pasta com sublinhado, todos os arquivos internos ficam expostos”. Arquivos comuns no App Router não são rotas por padrão. Um nome como _components não é um recurso de segurança obrigatório; ele é uma ferramenta organizacional que indica implementação interna e exclui a pasta do roteamento. nextjs.org
O terceiro equívoco é que “nomes de grupos de rotas também são incluídos nas URLs”. O nome entre parênteses em (marketing) é excluído da URL. Por causa dessa conveniência, você deve garantir que grupos diferentes não criem a mesma URL final. Se você dividir vários layouts raiz, a possibilidade de um carregamento completo da página ao navegar entre grupos é outro ponto a considerar antes de projetar a estrutura. nextjs.org
Por fim, evite o erro de manter diretórios app ou pages correspondentes tanto na raiz quanto em src ao introduzir src. Como a raiz tem precedência nesse caso, pode parecer que o código-fonte que você esperava não está sendo executado. Alterar uma estrutura não é simplesmente uma tarefa de adicionar todas as pastas de uma só vez; avance verificando qual diretório realmente serve como base para o roteamento. nextjs.org
Conclusão: o padrão está nos limites de responsabilidade, não em uma lista de pastas
O ponto de partida para uma estrutura de projeto Next.js são as convenções de roteamento definidas por app e pelos arquivos especiais. Em um novo projeto com App Router, você pode usar src/app como centro para URLs, páginas e layouts; manter public como a pasta de recursos estáticos na raiz; e escolher components, features, lib, hooks e types de acordo com o escopo real de reutilização do código e a complexidade do domínio. nextjs.orgnextjs.org
Em última análise, uma boa estrutura não é aquela com o maior número de pastas. É aquela em que os membros da equipe conseguem prever facilmente a localização de uma tela para uma rota específica, do código dedicado a essa tela e do código compartilhado em vários lugares. Siga precisamente as convenções de arquivos do Next.js e, em seguida, ajuste gradualmente a abordagem organizacional acima delas conforme a taxa de crescimento e os padrões de mudança do projeto evoluírem.