My company uses Major.Minor.Patch.Build for our version numbers. When a new release is started, the Major.Minor.Patch part is set. Then as work is done, the build number goes up until a build is deemed good enough. When that happens, then that Major.Minor.Patch.Build is released to Testing. If it passes Testing, then I goes on to prod. If it fails testing, then it will go back to development, and the next attempt will increase the Patch number by 1. (New version numbers and builds only happen while the release is in the Dev part of the process.). This all works fantastic for my company.

But now we are trying to move to containers, Helm charts and Kubernetes. This ecosystem seems to really love SemVer V2. As I am trying to grapple with this situation, I see two options to get build numbers into SemVer V2:

  1. Put it into a prerelease tag. Something like: 1.3.2-build.21. This works, but it is considered a "prerelease" build. So if I just use it as a normal build, then version precedence will always favor 1.3.2 over 1.3.2-build.589. This seems ugly (and prone to errors).

  2. Put in the metadata. Something like: 1.3.2+build.21. This is no longer prerelease, but 1.3.2+build.21 is considered the same as 1.3.2+build.589 for version precedence.

I can kind of understand what SemVer V2 is attempting here. From my consumer's point of view, the build number is extra detail. (A consumer of my software should never see two Major.Minor.Patch versions of the application that are different.)

But my dev teams need to keep it clear which build is which. So just using Major.Minor.Patch alone is not going to work.

And our CI/CD pipeline tools do automatic sorting and picking based on SemVer V2 precedence. So the meta data approach is not going to work.

I don't like the idea of using prerelease builds a normal releases. So I have eliminated that from full use.

Another option is to use Major.Minor.Build. (Replace the patch number with the build number.) While I could do that, it would be a hard sell for my company to give up the Patch number. (And it just seems kind of wrong.)

Our processes don't allow me to change the version number at the time we release to production. To change the version number of a tested and ready for prod build from a pre-release version number to a release version number would require one of the following:

  1. Another build (that then has to be tested again)
  2. Modifying the binaries (which then have to be tested again)

(I work in a medical field where mistakes can be really bad, so we have some strict testing rules.)

Right now I am going for a "fake it" approach. On surface we are still using a Major.Minor.Patch.Build. But integrate with my CI/CD tools, I am attempting to fake them out. I give them a container image that is tagged as prerelease for a deployment to Dev. And I build my helm chart dynamically at deploy time.

When I deploy to Test, I am adding another tag to the container image (the release version number). I again create a dynamic created Helm chart for deployment (this time using a release version number). I repeat the dynamic helm chart for the production deployment.

Dynamic helm charts, on the fly retagging during deployments... It all feels a bit ugly. But I can't see any way around this consumer focused limitation in SemVer V2.

But I got to thinking, maybe I am not the only one with this issue. Maybe someone already has a solution. So I thought I would ask:

How can can one deal with SemVer V2 integration in CI/CD tools and yet still use a build number in your development and deployment processes?

  • 1
    Can you elaborate on your "fake it" approach? Are you saying that you apply the 1.3.2 tag to the 1.3.2-build.589 build, assuming that build 589 is the one that passes testing and has no further changes? If so, can you elaborate more on the problems that you are facing? This approach is what I'd do, so I'm curious as to the specific issues you're running into.
    – Thomas Owens
    Commented May 22, 2021 at 8:26
  • Can you elaborate what you mean with "But my dev teams need to keep it clear which build is which."? Also, is any team outside the Dev team ever going to see different build numbers for a single Major.Minor.Patch version? Also, is the version number encoded in the name of the binary and if so, does that need to match exactly with the version number reported on the interface (API or GUI) or is there some fudge factor possible? Commented May 22, 2021 at 12:36
  • What's not clear here is what is the problem. Is it specifically that helm requires three place version numbers?
    – joshp
    Commented May 22, 2021 at 14:09
  • semver v2 supports build numbers 1.2.3-prerelease+4 semver.org
    – Ewan
    Commented May 22, 2021 at 15:14
  • @ThomasOwens - This is what I probably going to have to do. I don't like it because I have to create a dynamic Helm chart to make it work. This is because my deployment tool (Octopus Deploy) does not want to me to change the target package that was promoted from Dev to Test as it goes to promote from Test to Prod. Dynamically created helm charts seem like a bad practice.
    – Vaccano
    Commented May 24, 2021 at 18:00

3 Answers 3


What we do is major.minor.patch-build. So 1.3.2-589. We think it's a fairly common approach. It's also compatible with rpms, which we use for distributing some of our software.

So if I just use it as a normal build, then version precedence will always favor 1.3.2 over 1.3.2-build.589. This seems ugly (and prone to errors).

If you never create a 1.3.2, then it doesn't matter if version precedence favors it over 1.3.2-589. If you ever do create a 1.3.2, just ensure you do it after all the -build versions.

  • This seems a practical approach to keeping OP's process and version+build.
    – joshp
    Commented May 23, 2021 at 5:02
  • I may have to go with this. It just feels wrong to have all my releases be pre-release version numbers.
    – Vaccano
    Commented May 24, 2021 at 18:09

To make it compatible with SemVer, your workflow needs some changes:

  • When a new release is started, you start with <major>.<minor>.<patch>-build.0 (or ...1 if you're more of positive person).
  • The Dev/Testing cycle continues as normal.
  • When Testing clears a build for release, the relevant version <major>.<minor>.<patch>-build.<n> is "blessed" and without any non-trivial changes [1] promoted to version <major>.<minor>.<patch>.

This way, SemVer ordering is preserved for all versions, both internal and released. The users and/or customers do not see any release that includes a build number, and your team will know that the version without a build number is the one that was released. And your team will know which patches did not get through testing, because there is no version in your system for those patches without build number.

You indicated that you do not like prerelease builds, but to me it looks like that's exactly what these builds are anyway. Maybe I'm misunderstanding something, so feel free to elaborate in a comment.

[1] If the build artefacts must include the full version number, run a final build that doesn't include the pre-release part of the version number in the build artefacts, but it should be identical otherwise.


So your key problem here to my mind is this : "And our CI/CD pipeline tools do automatic sorting and picking based on SemVer V2 precedence"

Obviously if you are going to do more than one build of a patch version your CI/CD must understand that the build number affects precedence in some way.

If you can alter this to look at the build number then you can use SemVer with the build number in the semver defined place, ie. 1.2.3+4

If you can't then you just have to update the patch number.

I guess the problem from the CICD/SemVer perspective is that a build number alone doesn't indicate that the build is a higher version. Consider my master branch is at and my feature branch is at I've done a tonne of builds, but the feature hasn't been merged, if some other dev builds their random branch next they will get and so on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.