Semantic versioning e o seu changelog
5 min de leitura
Semantic versioning diz a quem chama quanto um lançamento pode doer antes que ela leia uma única
entrada do changelog. Ir de 2.4.1 para 2.5.0 diz: capacidade nova, nada quebra. Ir de 2.5.0
para 3.0.0 diz: leia essa entrada antes de atualizar. Changelog e número de versão deveriam
afirmar a mesma coisa em dois formatos, e a maior parte do atrito entre eles aparece exatamente
quando eles não concordam, o que acontece mais frequentemente do que a especificação sugeriria.
O que cada número em uma versão realmente promete?
Semantic versioning define três números, MAJOR.MINOR.PATCH, cada um com
uma regra estrita sobre o que o dispara. Um salto MAJOR significa uma mudança incompatível: algo
que uma integração correta e existente poderia notar e por causa da qual precisaria mudar. Um
salto MINOR significa nova funcionalidade compatível com versões anteriores: nada existente
quebra, algo novo fica disponível. Um salto PATCH significa uma correção compatível com versões
anteriores: o comportamento se aproxima do que estava documentado, e ninguém que dependia de
propósito do comportamento antigo deveria notar nada.
| Salto | Significado | A entrada deveria soar como |
|---|---|---|
MAJOR (1.x.x -> 2.0.0) | Uma mudança incompatível | “Precisa de ação antes de atualizar” |
MINOR (1.2.x -> 1.3.0) | Nova capacidade compatível | “Já está disponível, nada mais mudou” |
PATCH (1.2.3 -> 1.2.4) | Uma correção compatível | “Agora se comporta como estava documentado” |
A tabela também é um teste ao contrário: se uma entrada não lê como sua linha, ou o número de versão está errado, ou a entrada está subvendendo ou supervendendo o que realmente aconteceu.
O que conta como incompatível para fins de versionamento?
O mesmo teste que decide se algo pertence a um changelog de API: se quem chama corretamente, escrito contra o comportamento antigo e não tocado desde então, poderia se comportar diferente por causa dessa mudança. O que é uma mudança incompatível, e como lançá-la cobre a decisão por completo, incluindo casos que parecem incompatíveis e não são, e os que parecem pequenos e não são. Resumindo para fins de versionamento: se a resposta é sim, o salto é MAJOR independentemente de quanto código a mudança realmente tocou internamente. Números de versão acompanham a consequência para quem chama, não o esforço do time.
Como uma entrada de changelog deveria corresponder a um salto de versão?
Uma entrada, uma categoria de salto, dita logo de cara. O padrão da tabela continua diretamente: uma entrada incompatível fica sob a versão que a introduziu, formulada primeiro como um aviso e depois como uma descrição. Uma entrada aditiva fica sob sua versão MINOR, formulada como disponibilidade. Uma correção fica sob sua versão PATCH, formulada como uma correção. Misturar categorias em uma entrada, como dobrar uma mudança incompatível no mesmo parágrafo de uma correção sem relação, é como uma leitora acaba perdendo exatamente a única coisa que realmente importava.
## 3.0.0 (2026-09-07)
### Changed
- **BREAKING:** `GET /reports` agora retorna valores como inteiros na
menor unidade monetária (centavos) em vez de decimais. Atualize
qualquer código que leia `amount` diretamente.
## 2.9.0 (2026-09-01)
### Added
- Relatórios agora podem ser filtrados por `status`.
## 2.8.4 (2026-08-28)
### Fixed
- `GET /reports?status=` retornava uma página vazia em vez de um 400
para um status desconhecido.
Lido de cima para baixo, o número de versão e a etiqueta da seção dizem a mesma coisa duas vezes, e é exatamente esse o objetivo: uma leitora que só passa os olhos pelos títulos já tem uma leitura correta do risco antes de abrir uma única linha.
A regra de mudança incompatível vale do mesmo jeito antes de 1.0.0?
Não, e é daí que vem a maior parte da confusão sobre “isso era mesmo incompatível”. O SemVer é
explícito que a versão major zero, 0.y.z, é para desenvolvimento inicial: qualquer coisa pode
mudar a qualquer momento, e a API pública não deveria ser considerada estável. Um salto de 0.4.0
para 0.5.0 pode carregar uma mudança incompatível sem violar a spec, porque a garantia de versão
major só começa quando um projeto lança 1.0.0. Uma entrada de changelog ainda deve à leitora a
mesma honestidade sobre o que quebrou; o que muda é só que o número de versão em si não é o sinal
em que se apoiar antes de 1.0.0 chegar.
E se o seu produto não lança versões discretas?
A maioria dos produtos SaaS faz deploy contínuo e nunca mostra um número de versão a quem chama, o que não elimina a necessidade dessa disciplina, só o número que normalmente a carregaria. A entrada de changelog precisa fazer todo o trabalho sozinha: dizer claramente se uma mudança é incompatível, aditiva, ou uma correção, com as mesmas três palavras que semantic versioning usa, mesmo sem um campo de versão para anexá-las. Alguns times mantêm uma versão puramente interna só para ancorar entradas de changelog a algo que pode ser linkado, sem nunca mostrá-la diretamente a quem chama.
Como isso se aplica especificamente a um changelog de API?
De forma mais estrita do que quase em qualquer outro lugar, porque quem chama uma API é código,
não pessoas que podem dar de ombros para uma mudança inesperada. Changelog de API: o que
publicar e quem lê cobre a forma completa desse documento; a disciplina de
versionamento aqui é o que mantém honestas suas seções breaking e aditivas. Uma API que oferece
várias versões ao mesmo tempo, como v1 e v2 servidas em paralelo durante uma janela de
migração, está efetivamente aplicando semantic versioning na escala de toda a interface em vez de
um único pacote, e o mesmo vocabulário de três palavras ainda se aplica a cada entrada.
O que o Keep a Changelog diz sobre versionamento?
Ele se conecta diretamente pelo nome ao semantic versioning e recomenda o mesmo vocabulário de categorias que este artigo usa: Added, Changed, Deprecated, Removed, Fixed, Security. Keep a Changelog, na prática percorre como adotar essa especificação, incluindo onde os times costumam se desviar dela. A sobreposição não é coincidência: as duas especificações tentam resolver o mesmo problema de pontas opostas, uma padroniza o número de versão e a outra a entrada que o explica.
FAQ
Toda entrada de changelog precisa de um número de versão? Se o produto lança versões, sim, porque o número permite que uma leitora pule direto para “o quanto isso me afeta” sem ler a entrada primeiro. Se o produto faz deploy contínuo sem campo de versão, a formulação da entrada precisa carregar esse sinal sozinha.
Qual é a diferença entre um salto MAJOR e uma entrada de mudança incompatível? Eles deveriam descrever o mesmo evento de duas formas. O número de versão é o sinal legível por máquina (as ferramentas de quem chama podem reagir a ele); a entrada de changelog é a explicação legível por humanos do que exatamente mudou.
Um lançamento PATCH pode ser incompatível? Por definição, não deveria. Se um saiu mesmo assim, não editem nem refaçam a tag da versão publicada: a FAQ do SemVer diz para lançar uma nova versão que restaure a compatibilidade, ou uma nova MAJOR se a quebra continuar, e documentar a versão problemática para que os usuários saibam que devem pulá-la.
Mudanças puramente internas precisam de um salto de versão? Não. Semantic versioning acompanha a interface pública. Uma refatoração sem efeito observável para quem chama não precisa nem de salto nem de entrada de changelog, mesmo que internamente tenha sido um trabalho de engenharia significativo.
As afirmações técnicas deste artigo não foram revisadas de forma independente. Se algo estiver errado, avise a gente e vamos corrigir.