Publicado em
- 6 minutos de leitura
Arquitetura de pastas em Angular

A forma como estruturamos as pastas e arquivos em um projeto Angular é um dos pilares para garantir sua longevidade, manutenibilidade e escalabilidade.
Uma dúvida comum, especialmente para quem está começando, é como ir além da estrutura padrão gerada pelo Angular CLI.
Embora não exista uma única “bala de prata”, a comunidade e a experiência em projetos de larga escala consolidaram uma abordagem robusta e intuitiva que facilita o trabalho, principalmente quando o projeto cresce e novas pessoas entram no time.
Mais do que apenas organizar arquivos, uma boa arquitetura de pastas define limites claros.
Ela estabelece onde uma responsabilidade começa e termina, como as diferentes partes da aplicação podem interagir e, crucialmente, o que elas não podem fazer.
Adotar uma estrutura bem pensada desde o início é um investimento que previne o débito técnico, reduz a complexidade e acelera o desenvolvimento a longo prazo, permitindo que a aplicação cresça de forma saudável e organizada.
Se preferir, assista o vídeo diretamente no YouTube:
Os Três Pilares da Estrutura: core
, features
e shared
A base da nossa estrutura recomendada se apoia em três diretórios principais dentro de src/app
: core
, features
e shared
.
Cada um possui uma responsabilidade clara e distinta, ajudando a classificar cada novo arquivo ou funcionalidade no lugar certo.
core
: O núcleo da aplicação, contendo tudo que é essencial e carregado uma única vez.features
: As diferentes funcionalidades ou domínios de negócio da sua aplicação.shared
: Recursos reutilizáveis que podem ser consumidos por diferentes funcionalidades.
A Pasta core
: O Núcleo da Aplicação
A principal regra da pasta core
é simples: coloque aqui tudo aquilo que é fundamental para a aplicação e, conceitualmente, instanciado apenas uma vez no nível da raiz.
É o lugar ideal para serviços singleton, interceptors, guards e outras lógicas de inicialização que são, por natureza, globais.
O que colocar aqui?
- Componentes de Layout: Componentes estruturais como
LayoutComponent
,HeaderComponent
,FooterComponent
, que definem a “casca” da aplicação. - Serviços Essenciais, Guards e Interceptors: Lógicas de proteção de rota (
AuthGuard
) e interceptadores de requisições HTTP (AuthInterceptor
) que atuam globalmente. - Initializers (
APP_INITIALIZER
): Funções que precisam rodar durante a inicialização do Angular para configurar ou carregar dados essenciais.
Boa Prática: Para manter o arquivo app.config.ts
limpo e legível, é uma ótima prática criar funções de provider dentro do core
.
Por exemplo, uma função provideCore()
pode encapsular todos os providers relacionados ao core
, simplificando o registro na aplicação.
// src/app/core/core.providers.ts
import { provideHttpClient, withInterceptors } from '@angular/common/http'
import { authInterceptor } from './interceptors/auth.interceptor'
import { EnvironmentProviders, Provider } from '@angular/core'
export function provideCore(): (Provider | EnvironmentProviders)[] {
return [
provideHttpClient(withInterceptors([authInterceptor]))
// Outros providers do core...
]
}
// src/app/app.config.ts
import { ApplicationConfig } from '@angular/core'
import { provideRouter } from '@angular/router'
import { routes } from './app.routes'
import { provideCore } from './core/core.providers'
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideCore() // Mantém o app.config limpo e declarativo
]
}
A Pasta features
: Módulos de Funcionalidade com Lazy Loading
Esta é a pasta onde a maior parte da sua aplicação viverá.
Cada subpasta dentro de features
representa uma funcionalidade de negócio autocontida, como products
, checkout
, ou profile
.
A ideia é que cada feature seja o mais independente possível.
Roteamento Inteligente:
Uma prática poderosa é fazer com que o roteador principal (app.routes.ts
) carregue um arquivo de rotas específico de cada feature (feature.routes.ts
) em vez de um único componente.
Isso, combinado com lazy loading, delega a responsabilidade do roteamento interno para a própria feature, mantendo o roteador principal enxuto e focado em orquestrar as áreas da aplicação.
// src/app/app.routes.ts
import { Routes } from '@angular/router'
export const routes: Routes = [
{
path: 'products',
// Carrega o arquivo de rotas da feature de produtos
loadChildren: () => import('./features/products/products.routes').then((m) => m.PRODUCT_ROUTES)
}
// ... outras rotas de features
]
// src/app/features/products/products.routes.ts
import { Routes } from '@angular/router'
import { ProductListComponent } from './pages/product-list/product-list.component'
import { ProductDetailComponent } from './pages/product-detail/product-detail.component'
// A feature gerencia suas próprias rotas
export const PRODUCT_ROUTES: Routes = [
{
path: '',
component: ProductListComponent
},
{
path: ':id',
component: ProductDetailComponent
}
]
A Pasta shared
: Recursos Genuinamente Reutilizáveis
A pasta shared
é destinada para componentes, diretivas, pipes e modelos que são reutilizados em múltiplas features.
Se um componente de card
é usado tanto na listagem de produtos quanto no carrinho de compras, ele pertence a shared
.
Shared
não deve conter serviços que são fundamentais para a estrutura da aplicação; esses pertencem ao core
.

Como Decidir Onde Colocar um Recurso (core
vs. shared
)
A dúvida sobre alocar um recurso na pasta core
ou shared
é muito comum.
A regra de decisão é a mesma para qualquer tipo de recurso – sejam serviços, componentes, diretivas ou pipes – e se baseia em quem o consome.
-
Coloque o recurso em
core
se: Ele for consumido exclusivamente por outro recurso que já pertence aocore
. Por exemplo, se umAuthInterceptor
(que está nocore
) precisa de umTokenStorageService
, então oTokenStorageService
também deve ficar nocore
. Da mesma forma, umLogoutButtonComponent
usado apenas dentro doHeaderComponent
(que faz parte do layout nocore
) também pertence aocore
. Isso mantém o núcleo autocontido. -
Coloque o recurso em
shared
se: Ele foi projetado para ser reutilizável e é consumido por múltiplasfeatures
, mas não por nada nocore
. Por exemplo, umPriceFormatPipe
, umCardComponent
genérico ou umTransactionsService
que é usado pelas featureshome
ereports
são candidatos perfeitos para a pastashared
.
Escalando o Projeto: Vantagens para Múltiplas Equipes e Longo Prazo
Adotar essa estrutura desde o início traz benefícios imensos, especialmente em cenários complexos.
Autonomia e Paralelismo: Com funcionalidades claramente isoladas em suas próprias pastas, diferentes equipes podem trabalhar em paralelo com um risco mínimo de conflitos.
A Equipe A pode desenvolver a feature de “profile” enquanto a Equipe B trabalha no “dashboard” sem interferir uma na outra.
Redução de Débito Técnico: A estrutura previne o acoplamento excessivo entre as partes do sistema.
Isso evita que o projeto se torne um “emaranhado de dependências” com o tempo, tornando as manutenções futuras mais rápidas e seguras.
Consistência e Previsibilidade: Um novo desenvolvedor ou alguém que muda de equipe consegue entender rapidamente onde encontrar os arquivos e como a aplicação está organizada, acelerando sua produtividade e reduzindo a curva de aprendizado.
Regras de Dependência: Definindo os Limites da Arquitetura
Para que a estrutura funcione, é vital respeitar uma regra de fluxo de dependências.
A arquitetura se fortalece com limites claros.
- O Fluxo Correto:
features
podem depender decore
eshared
.shared
pode depender decore
.
- O Anti-Padrão a ser Evitado:
core
NUNCA deve depender deshared
oufeatures
.
O núcleo da aplicação deve ser agnóstico às funcionalidades e aos componentes compartilhados.
Se o core
precisar de algo de uma feature, provavelmente essa lógica deveria estar no próprio core
.
Quebrar essa regra cria dependências circulares e destrói o propósito do isolamento, tornando o projeto frágil e difícil de manter.
Conclusão: Construindo para o Futuro
Estruturar um projeto Angular com as pastas core
, features
e shared
, e respeitar um fluxo de dependência claro, é uma estratégia poderosa para construir aplicações robustas e escaláveis.
Essa abordagem promove o baixo acoplamento e a alta coesão, princípios fundamentais da engenharia de software que facilitam a manutenção, os testes e o trabalho em equipe.
Ao definir limites claros desde o início, você garante que sua aplicação possa crescer de forma sustentável, adaptando-se a novas regras de negócio e tecnologias sem a necessidade de grandes e arriscadas refatorações.
A consistência e a disciplina em manter essa organização são o que garantem um projeto saudável e produtivo a longo prazo.
Assine nossa Newsletter
Receba novos posts como esse na sua caixa de e-mail!
Sobre o autor
