Estrutura projeto Node.js: guia profissional do zero
Montar a estrutura projeto Node.js do jeito certo evita retrabalho. Veja um passo a passo com pastas, camadas e boas práticas para escalar sem dor de cabeça.
Montar a estrutura projeto Node.js do jeito certo evita retrabalho. Veja um passo a passo com pastas, camadas e boas práticas para escalar sem dor de cabeça.
Uma estrutura projeto Node.js bem definida é o que separa um código que dá manutenção de um que vira um pesadelo. Quando você organiza pastas e responsabilidades logo no início, evita retrabalho, facilita testes e deixa o time (ou você mesmo, meses depois) entendendo o projeto rapidamente. Este guia mostra um caminho prático, do zero, que funciona para APIs e aplicações backend em geral.
Pré-requisitos: Node.js instalado (versão LTS), npm ou yarn, e um editor de código. Se você está começando, não precisa de mais nada além disso.
Passo 1: Crie a pasta raiz e o package.json
Todo projeto Node.js começa com um package.json. Se você ainda não tem, rode npm init -y na pasta do projeto. Esse arquivo guarda dependências, scripts e metadados.
Dica: defina "type": "module" no package.json para usar import/export (ESModules) em vez de require. É o padrão moderno e facilita a leitura.
Erro comum: deixar o package.json bagunçado com scripts que ninguém entende. Mantenha apenas o essencial: start e dev.
Passo 2: Estruture a pasta src
A pasta src concentra todo o código da aplicação. Ela separa o que é seu do que é configuração ou build. Dentro dela, crie subpastas por responsabilidade.
Estrutura mínima recomendada:
projeto/ ├── src/ │ ├── config/ │ ├── controllers/ │ ├── models/ │ ├── routes/ │ ├── services/ │ └── app.js ├── .env ├── .gitignore └── package.json
Dica: não coloque tudo na raiz. Um arquivo solto como server.js na raiz pode até funcionar, mas mistura o que é configuração com o que é código de aplicação.
Erro comum: criar pastas vazias como utils ou helpers sem critério. Só crie uma pasta quando houver pelo menos dois arquivos que compartilhem aquele propósito.
Passo 3: Separe as camadas: routes, controllers, services e models
Essa é a parte central da estrutura projeto Node.js. Cada camada tem um papel:
- routes: definem os endpoints e métodos HTTP (GET, POST, PUT, DELETE).
- controllers: recebem a requisição, validam dados básicos e chamam o service.
- services: contêm a regra de negócio. É aqui que a lógica real acontece.
- models: representam os dados e a interação com o banco.
Exemplo prático: para uma rota /users, você teria routes/userRoutes.js, controllers/userController.js, services/userService.js e models/User.js. A rota chama o controller, o controller chama o service, e o service usa o model.
Dica: mantenha os controllers enxutos. Se um controller passa de 30 linhas, provavelmente a lógica deveria estar no service.
Erro comum: colocar regra de negócio no controller. Isso dificulta testes e reuso. O controller só orquestra.
Passo 4: Use um arquivo de entrada enxuto (app.js)
O app.js é o ponto de entrada da aplicação. Ele deve apenas configurar o express (ou outro framework), registrar as rotas e iniciar o servidor. Nada de lógica complexa aqui.
Exemplo simples:
import express from 'express'; import userRoutes from './routes/userRoutes.js';
const app = express(); app.use(express.json()); app.use('/users', userRoutes);
export default app;
Dica: separe a configuração do servidor de sua inicialização. Crie um server.js na raiz (ou em src/) que importa o app e escuta a porta. Isso facilita testes com supertest.
Erro comum: colocar tudo no server.js e depois ter dificuldade para testar ou reutilizar a aplicação.
Passo 5: Configure variáveis de ambiente
Nunca coloque senhas, chaves de API ou URLs de banco direto no código. Use um arquivo .env na raiz e a biblioteca dotenv para carregar as variáveis.
Exemplo de .env:
PORT=3000 DB_URL=mongodb://localhost:27017/meuprojeto JWT_SECRET=segredo_super_secreto
Dica: adicione o .env ao .gitignore imediatamente. Você não quer subir segredos para o repositório.
Erro comum: versionar o .env ou criar um .env.example com valores reais. O .env.example deve conter apenas os nomes das variáveis, sem valores sensíveis.
Passo 6: Crie um .gitignore desde o início
Mesmo que o projeto seja local, crie o .gitignore antes do primeiro commit. Ele evita que node_modules, .env e arquivos de log vão para o repositório.
Conteúdo mínimo:
node_modules/ .env *.log
Dica: você pode gerar um .gitignore padrão para Node.js no site gitignore.io. Isso cobre mais casos, como arquivos de build e cache.
Erro comum: esquecer o .gitignore e subir node_modules (que pode ter milhares de arquivos) ou pior, subir o .env com credenciais.
Passo 7: Adicione scripts úteis no package.json
Os scripts padronizam comandos comuns. Além de start e dev, adicione test e, se usar ESLint, lint.
Exemplo:
"scripts": { "start": "node src/server.js", "dev": "node --watch src/server.js", "test": "node --test" }
Dica: use node --watch (Node 18+) para reiniciar o servidor automaticamente em desenvolvimento, sem precisar de nodemon.
Erro comum: criar scripts com nomes ambíguos como start:dev e start:prod sem documentar o que cada um faz.
Checklist final: o que você deve ter agora
- [ ] Pasta
srccom subpastasconfig,controllers,models,routeseservices. - [ ]
app.jsenxuto que apenas configura o Express e registra rotas. - [ ]
server.jsseparado que inicia o servidor. - [ ]
.envcom variáveis de ambiente e.env.examplecom nomes apenas. - [ ]
.gitignorecomnode_modules/,.enve*.log. - [ ] Scripts
start,devetestnopackage.json.
FAQ
Qual a diferença entre controllers e services?
Controllers lidam com a requisição HTTP: recebem dados, validam formato básico e devolvem a resposta. Services contêm a regra de negócio, como cálculos, validações complexas e integrações. Separar os dois permite testar a lógica sem depender do HTTP.
Posso usar essa estrutura para projetos pequenos?
Sim, mas adapte. Para um projeto de estudo ou uma API mínima, você pode começar com apenas routes, controllers e models. A estrutura completa faz mais sentido quando o projeto tende a crescer ou ter mais de uma pessoa trabalhando.
Preciso usar Express? Posso usar outro framework?
A estrutura funciona com qualquer framework, como Fastify ou NestJS. A lógica de separar camadas (routes, controllers, services) é agnóstica. O Express é o mais comum, mas o princípio de organização é o mesmo.
Onde coloco arquivos de configuração, como banco de dados?
Na pasta src/config. Crie arquivos como db.js ou env.js que exportam configurações carregadas do .env. Isso centraliza e facilita a manutenção.
Como lidar com autenticação nessa estrutura?
Crie um middleware, por exemplo src/middlewares/auth.js, e aplique nas rotas que precisam de proteção. O middleware valida o token e injeta os dados do usuário na requisição, que o controller repassa ao service.
É melhor usar JavaScript ou TypeScript?
TypeScript adiciona tipagem estática, o que ajuda em projetos grandes. A estrutura de pastas é a mesma. Se você está começando, JavaScript é suficiente; mas se o projeto vai crescer, considerar TypeScript desde o início economiza refatoração depois.