Back Original

Conventional Commits encourages focus on the wrong things

You’ve almost certainly encountered Conventional Commits before. It may have reared its ugly head in the changelog of an open source project you’ve used. It may have been the enforced commit format for an open source project you contributed to. A lot of people swear by it. I swear at it.

Even though it is used by a large number of popular open source projects, Conventional Commits is an actively bad standard which encourages focus on the wrong things and fails to deliver on its promises.

Focus Failure

Conventional Commits promises to add semantic meaning to commit messages to aid developers and end-users in understanding the changes made in a commit. However, Conventional Commits fails to do this in spectacular fashion. To demonstrate this, let’s look at the anatomy of a conventional commit. According to the Conventional Commit website commit messages should be formatted as follows:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

The commit’s subject line has a <type> (something like fix, feat, chore, docs, or refactor1) describing the type of change. Following that, there is an optional scope, and then a description.

This format has a major failing: type is prioritised over scope. This is exactly backwards.

Scope > Type

The scope of a change (the subject of the change) is the most important part of a commit. To demonstrate this, let’s consider why each one of the following stakeholders care about the scope of the change more than the type of the change:

So what does Conventional Commits do? It deprioritises scope so much that it’s optional! Why the hell is scope optional? Having a commit without a scope is like having a sentence without a subject! Then, to add insult to injury, Conventional Commits elevates type to the front of the commit message. Conventional Commits gets the priority of scope and type entirely wrong.

Type is Redundant and Restrictive

You might be thinking “so it may be backwards, but commit type is at least still important, right?” and to that I say “no”. A commit’s description should almost always tell you the type of the change! Consider this commit message as an example:

fix(compiler): prevent namespaced SVG <style> elements from being stripped

Even if you only had the description, it’s obvious that it was a bugfix! Space on the subject line of a commit is already at a premium, wasting characters on the type is not helpful! But it’s often even worse than useless; it’s often restrictive. Take this commit message as an example:

refactor(core): Update webmcp support to use document.modelContext

This commit updated the webmcp functionality in the core component to support both document.modelContext and navigator.modelContext, so was that a bugfix, refactor, or new feature? I would argue it’s all of them! But again, the only thing that really matters is that it was a change to the core/webmcp component.

Conventional Commits fundamentally focuses on the wrong thing (the commit type) and devalues the scope (which is what people actually care about).

Broken Promises

So we have determined that the format of Conventional Commits sucks, but it must provide some benefit. Let’s read the Why Use Conventional Commits section to see if any of the reasons make any sense.

Not a single one of the “selling points” for Conventional Commits actually holds water.

Conventional Commits is also extremely difficult to apply to a project. You are supposed to define your own set of “types”, but pretty much everyone just takes the defaults from commitlint which often don’t fit well with the particulars of individual projects. This problem is especially acute in corporate environments where change management and audit requirements often mandate a ticket number in every commit message. The <scope> field is the obvious place to put it, but this ends up replacing the only useful metadata in a Conventional Commit with a completely useless ticket number.

A Better Way

So what should you do instead? Follow the lead of truly successful software projects like Linux, FreeBSD, Git, Go, and NixOS! What do these projects have in common? They all use scope-prefixed commit messages (where “scope” is defined to be relevant to the actual project). Usually, the scope to use on a given project is self-evident. For the Linux kernel, the subsystem is the natural scope. For Go projects, the package path is the natural scope. For a project using a microservice architecture, the microservice name is the natural scope.

Here are some examples of projects and their commit format guidelines.

ProjectFormatExample
Linuxsubsystem: descriptioni2c: virtio: mark device ready before registering the adapter
FreeBSDprefix: Descriptionlinuxulator: Return EINVAL for invalid inotify flags
Gitarea: descriptiongitlab-ci: update macOS image
Gopackage: descriptionnet/http/cookiejar: add godoc links
nixpkgspkg-name: descriptionxwayland: 24.1.11 -> 24.1.12
Node.jssubsystem: descriptionstream: fast-path stateless transform flush results

Unfortunately, despite being used by some of the most successful open source projects ever created, this commit style seems to have lost the branding war. I intend to change that. Introducing scopedcommits.com. The website is dedicated to advocating for a return to commit message sanity, and separating the concern of changelog generation from commit log management.

Conclusion

Conventional Commits’ purported advantages are actually illusory and the industry has seen no tangible benefit from using it as a standard. However, Conventional Commits unfortunately seems to have become fairly popular in open source projects, and due to this it seems like AIs have a habit of defaulting to using it for commit messages. This has caused propagation of anti-pattern-ridden commit messages across projects.

My goal in this article is to fight against Conventional Commits’ dominance, and demonstrate that there better ways to structure commit messages. But if this article has not convinced you to stop using Conventional Commits, I look forward to the flame war in the comment section.