Explainer: version and build numbers

Version numbering of macOS and its software is confusing, inconsistent, and completely absent from many key parts. This article sets out to explain how version and build numbers should work, how they do work, and how they don’t.

Software is intangible. Even when you can look inside it, it’s very difficult to know whether one copy of an app is the same as another. The purpose of numbering versions is to enable developers, system administrators and users to tell exactly which version is being used, and to know which is the more recent of two different versions.

Each time a product is built for testing, it’s normally given a build number, which should be unique to that major version of the product. Each time that product is built for testing by those outside the development team, it should also be given a new version number. This enables testers and developers to know exactly which version they are testing or referring to. This could be done with build numbers, but once a product is being released to larger numbers of testers, for example in a formal beta release, it’s better that this is recognised with a new version number.

Version numbering is usually structured, to indicate the degree of difference from previous versions. When Mac OS went from Classic Mac OS 9 to Mac OS X, this was clearly a major change, so the first of the version numbers changed from 9 to 10. The last version of Classic Mac OS was 9.2.2, and the first release version of Mac OS X was 10.0, which had a build number of 4K78. Although Apple seems to have had consistent rules over how to number versions, it has changed the way that it actually numbers major releases of Mac operating systems on at least two occasions, when it switched from Classic Mac OS to Mac OS X, and from macOS 10.15 Catalina to macOS 11 Big Sur.

It’s easy to see which version of macOS your Mac is running using the About This Mac command in the Apple menu, but to discover its build number you have to either click on the version number there, or on the System Report… button, then in System Information select Software at the left. The System Version given there consists of the version and build number, such as 11.4 (20F71), and System Information also shows the current version of the kernel that’s running, such as 20.5.0, which is different from but related to the macOS version number.

For an app, the everyday method of checking is to view the app in the Finder. This displays only the version number, and doesn’t ordinarily include any build number unless the app’s developer incorporates that into the version number. Otherwise, the only way to check the build number (without going into the app’s folder contents) is to open the app and its About window, where it’s customarily given in parentheses after the version number.

Command tools and other executable files are different again. Frameworks and other components which come in a bundle should provide a version number visible in the Finder, but few command tools or single-file executable binaries do so. Some have a command option such as -v which displays their version number, but in most cases there’s no version or build number which the user can view.

In macOS, version and build numbers are stored in the Info.plist Property List either inside a bundle (including regular apps), or concatenated within a Mach-O file in the case of single-file executable binaries. Two different keys are used there:

  • CFBundleShortVersionString, which is a user-visible text string containing the version number.
  • CFBundleVersion, which Apple describes as “a machine-readable string”, that isn’t intended for the user to see, and forms the build number.

Although these might appear almost identical, Apple has different rules for each; the roles they play and how they’re used are also essential to their understanding.

CFBundleShortVersionString provides the information displayed to the user in the Finder, and doesn’t appear to be analysed or manipulated in any other way. Apple prescribes: “The required format is three period-separated integers, such as 10.14.1. The string can only contain numeric characters (0-9) and periods.” But as you can see in various apps, because it’s treated as informative text, it can be used to distinguish different types of release, such as 4.6.2b3 for a third beta-release, and sometimes even incorporates the build number.

CFBundleVersion has a different purpose, and is used by LaunchServices, for example, to determine which version of an app is the most recent and should be used to open a file. Apple prescribes: “This key is a machine-readable string composed of one to three period-separated integers, such as 10.14.1. The string can only contain numeric characters (0-9) and periods.” “You can include more integers but the system ignores them. You can also abbreviate the build version by using only one or two integers, where missing integers in the format are interpreted as zeros. For example, 0 specifies 0.0.0, 10 specifies 10.0.0, and 10.5 specifies 10.5.0.”

For both, Apple prescribes how the three period-separated integers should be constructed:
“Each integer provides information about the release in the format [Major].[Minor].[Patch]:

  • Major: A major revision number.
  • Minor: A minor revision number.
  • Patch: A maintenance release number.”

You don’t have to look far in macOS to find examples of Apple’s own software which don’t comply with those rules. For example, Bluetooth File Exchange.app has a CFBundleVersion of 8.0.5d7, and Mail.app has a CFBundleShortVersionString of 14.0 but its CFBundleVersion is 3654.100.0.2.22. Normally, command tools in macOS don’t include an Info.plist within their Mach-O files, so don’t contain any readable version there, and even when run can’t identify which version they are.

But that’s just how macOS version and build numbers work.

Thanks to Reader for pointing out the hidden way to discover the macOS build number (below).