Conventional Commits no Node.js é uma convenção para escrever mensagens de commit com significado humano e legível por ferramentas. Prefixos como feat, fix e docs comunicam a intenção da mudança e permitem gerar changelog, calcular versões SemVer e automatizar releases.
A convenção não melhora commits apenas porque adiciona um prefixo. O valor aparece quando cada commit representa uma mudança coesa, a descrição explica o resultado e breaking changes incluem orientação de migração. Um histórico estruturado facilita revisão, investigação e automação.
Neste guia, você aprenderá a sintaxe, tipos, scopes, body, footers, breaking changes, commitlint, Husky, squash merge, CI e integração com Changesets e semantic-release.
Formato básico
<type>[scope opcional][!]: <descrição>
[body opcional]
[footer opcional]A especificação de Conventional Commits 1.0.0 exige tipo, dois-pontos, espaço e descrição.
feat
feat(api): adiciona filtro por statusfeat representa uma nova funcionalidade e normalmente corresponde a uma versão minor em SemVer.
fix
fix(cache): evita expiração duplicadafix representa correção de bug e normalmente corresponde a patch.
Breaking change
Use !:
feat(api)!: altera resposta de paginaçãoOu footer:
feat(api): adiciona cursor assinado
BREAKING CHANGE: `nextPage` foi substituído por `nextCursor`.Breaking change corresponde a major. Inclua como migrar, não apenas a frase “quebra API”.
Outros tipos
Tipos comuns:
docs: documentação;test: testes;refactor: mudança interna sem feature ou fix;perf: desempenho;build: build e dependências;ci: pipeline;chore: manutenção;style: formatação sem comportamento;revert: reversão.
A especificação só define efeito SemVer implícito para feat, fix e breaking changes. Ferramentas podem configurar outros efeitos.
Scope
fix(auth): rejeita refresh token expirado
feat(cli): adiciona saída JSON
perf(database): reduz consultas duplicadasO scope deve ser curto e estável. Use domínio, pacote ou componente, não nome de arquivo aleatório.
Descrição
Uma boa descrição:
- é curta;
- explica o resultado;
- usa linguagem consistente;
- evita ponto final quando a equipe adota essa regra;
- não repete o tipo.
Melhor:
fix(queue): confirma mensagem após persistênciaPior:
fix: ajustesBody
fix(payments): impede cobrança duplicada
A chave de idempotência agora é persistida antes da chamada ao gateway.
O fluxo anterior permitia duas cobranças quando o retry começava durante
uma falha de rede.O body explica contexto, decisão e efeitos colaterais.
Footers
fix(api): corrige validação de cursor
Refs: #123
Reviewed-by: Ana
Footers seguem formato semelhante a Git trailers. Tokens com espaços usam hífen, exceto BREAKING CHANGE.
Commits coesos
Se uma mudança contém feature, refactor e correção independentes, divida. Commits menores:
- facilitam revisão;
- permitem revert seletivo;
- geram changelog mais preciso;
- melhoram bisect;
- reduzem tipos ambíguos.
Squash merge
Nem todos os commits locais precisam obedecer à convenção quando a plataforma faz squash. O título final do pull request ou mensagem de merge pode ser validado e usado para release.
Esse modelo reduz carga para colaboradores externos, mas exige revisão cuidadosa do commit final.
Commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventionalCrie commitlint.config.mjs:
export default {
extends: ['@commitlint/config-conventional']
};Teste:
echo "feat(api): adiciona paginação" | npx commitlintHusky
npm install --save-dev husky
npx husky initCrie o hook .husky/commit-msg:
npx --no -- commitlint --edit "$1"Hooks locais oferecem feedback rápido, mas podem ser ignorados. A CI continua sendo a fonte de proteção.
Validando no CI
Em pull requests, valide títulos ou commits conforme a estratégia. Para squash merge, validar todos os commits individuais pode ser desnecessário.
Consulte CI para Node.js com GitHub Actions.
Regras personalizadas
export default {
extends: ['@commitlint/config-conventional'],
rules: {
'header-max-length': [2, 'always', 100],
'scope-enum': [2, 'always', [
'api',
'domain',
'cli',
'database',
'ci'
]]
}
};Uma lista de scopes pode ajudar, mas vira manutenção excessiva em projetos que mudam frequentemente.
Breaking changes com clareza
Mensagem insuficiente:
feat!: muda autenticaçãoMensagem útil:
feat(auth)!: exige PKCE no fluxo público
BREAKING CHANGE: clientes públicos devem enviar `code_challenge`
e `code_verifier`. Consulte o guia de migração em docs/pkce.md.Relação com SemVer
fix→ patch;feat→ minor;BREAKING CHANGEou!→ major.
Veja Semantic Versioning no Node.js.
Conventional Commits e Changesets
As ferramentas resolvem problemas diferentes:
- Conventional Commits estrutura o histórico;
- Changesets registra explicitamente pacote, bump e changelog.
Em monorepos, Changesets é mais explícito sobre múltiplos pacotes. Você pode usar ambos.
Veja Changesets no Node.js.
Conventional Commits e semantic-release
semantic-release analisa commits desde a última tag e calcula a próxima versão. Isso exige que mensagens finais sejam corretas. Um feat usado para refactor pode gerar minor desnecessária; um breaking change sem footer pode sair como minor.
Commits de dependências
Uma atualização de dependência pode ser:
build(deps)sem efeito de release;fix(deps)quando corrige comportamento publicado;- breaking quando remove suporte ou altera contrato.
Classifique pelo impacto no consumidor, não pela ferramenta que alterou o arquivo.
Perf
perf(parser): reduz alocações em arquivos grandesAlgumas automações tratam perf como patch. Configure conscientemente.
Revert
revert: remove cache de respostas
Refs: a1b2c3dO efeito de versão depende do que foi revertido e da ferramenta. Revise releases geradas automaticamente.
Idioma
A especificação não exige inglês. Escolha um idioma alinhado aos consumidores e mantenha consistência. Pacotes open source internacionais costumam usar inglês; equipes internas podem usar português.
Título de pull request
Quando o merge é squash, use:
feat(api): adiciona filtros de pedidosA descrição do PR fornece contexto, testes e screenshots, enquanto o título vira commit final.
Configuração da plataforma
Configure:
- squash como estratégia padrão;
- título do PR como mensagem;
- branch protection;
- check de commitlint;
- template com breaking change;
- release automation somente após merge.
Histórico não é changelog completo
Commits contêm detalhes técnicos; changelog deve agrupar mudanças e falar com consumidores. Ferramentas ajudam, mas textos ainda precisam de revisão.
Não reescreva histórico publicado
Corrija mensagens antes do merge com rebase ou squash. Depois de compartilhado, reescrever commits pode causar problemas. Uma classificação errada já lançada deve ser corrigida no próximo release e na documentação.
Exemplos
feat(search): adiciona filtro por data
fix(database): libera client após rollback
perf(json): evita serialização duplicada
docs(readme): adiciona exemplo ESM
test(auth): cobre rotação de refresh token
ci(release): publica com OIDC
build(deps): atualiza TypeScript
refactor(domain): extrai value object Money
feat(api)!: remove paginação por offset
BREAKING CHANGE: use `cursor` e `limit` no lugar de `page`.Erros comuns
- chore para tudo: histórico perde significado.
- fix em feature: versão calculada fica errada.
- breaking sem footer: major não é gerada.
- scope por arquivo: convenção fica instável.
- descrição “ajustes”: não comunica resultado.
- hook sem CI: pode ser ignorado.
- validar todos em squash: aumenta atrito sem benefício.
- automação sem revisão: changelog ruim é publicado.
Fluxo recomendado
- Faça commits coesos.
- Use tipo pelo impacto.
- Adicione scope útil.
- Explique contexto no body.
- Marque breaking changes.
- Valide localmente.
- Valide mensagem final no CI.
- Revise versão e changelog.
- Automatize somente após checks.
Conclusão
Conventional Commits no Node.js adiciona estrutura ao histórico com tipos, scopes e breaking changes. Essa estrutura melhora comunicação e permite automações baseadas em SemVer.
Use mensagens específicas, commits coesos e revisão da mensagem de merge. Com commitlint, CI e uma política de squash bem definida, a convenção ajuda releases sem transformar cada commit temporário em burocracia.




