Mobile App Versioning
First, please read this introduction about how to think about mobile app versioning. As an end user-facing application, a version number has different meaning than with e.g. libraries. The only technical requirement is that it needs to establish an ordering criteria so that app stores are able to determine which version is younger than others / the newest. Therefore, app versioning should be mostly about supporting our own workflows.
We use semantic versioning format (major.minor.patch
) for the frontend applications.
Semantics of major.minor.patch
We follow a free interpretation of the format (major.minor.patch) that does not convey any
semantics about backwards compatibility. Internally, we attach a build number for internal
reference (major.minor.patch.buildNumber
). Rationale:
- We use the major version 1 for all releases (for now)
- major will be incremented on frontend rewrites or changes that completely change how the frontends look/feel like for the users. intention would be to communicate big changes within the version number.
- Every app store release increments minor. Minor is incremented on every release, not in between releases.
- On every hotfix (via EAS Update) updates increases patch.
Pros & Cons
- ✅ Easy in internal communication (“we currently support backwards compatibility for 1.55.0 - 1.58.0”)
- ✅ Human readable / understandable which version is newer
- ✅ Allows upfront planning for PMs in Jira as the next release version “name” is always known upfront (in contrast to CalVer see below)
- ⛔️ might lead to feature-based release cycle thinking
- ✅ allows to switch to feature-based release cycle easily
- ✅ gives pointer to version control (indirectly via build system), ideally tag also in git to get rid of indirection
- ✅ allows resets of the build number (e.g. if/when migrating from gitlab → gitlab → github) while preserving the ordering required by app stores
- ✅ allows tracking of multiple builds per version (during stabilisation of a version for rollout) as featured by App Store Connect
- ✅ completely automatable as every build can be versioned + tagged without human intervention / planning
How to Map to Android & iOS Version Numbers
- Android (internally) uses monotonically increasing integers (
versionCode
) which can be increased with every build we do, users see string in semver format (versionName
). - iOS uses semver format
major.minor.patch
(CFBundleShortVersionString
) and allows additionalCFBundleVersion
to contain another arbitrary number (major.minor.patch.sthmore
).CFBundleShortVersionString
typically contains the version andCFBundleVersion
the build number, prefixed with the version to link the two (not technically required but sensible to do). - So, for a release
1.55.0
- Android will have a (potentially series of) builds e.g.
versionCode=5647
andversionName=1.55.0.1234
versionCode=5651
andversionName=1.55.0.1238
- in which
versionCode
needs to be larger than any previousversionCode
for builds uploaded to Play Store (published or not) and is therefore derived from what has been previously uploaded to Play Store - in which
versionName
is an “arbitrary” string displayed to the user, consisting of the release version1.55.0
and our internal build number (currently taken from GitLab, 1234 and 1238 in this example).
- iOS will (most likely) have the same series of build e.g.
CFBundleShortVersionString=1.55.0
andCFBundleVersion=1.55.0.1234
CFBundleShortVersionString=1.55.0
andCFBundleVersion=1.55.0.1238
- in which
CFBundleVersion
additionally links to our internal build number (currently taken from GitLab,1234
and1238
in this example) - in which
CFBundleShortVersionString
represents what the users see
- Android will have a (potentially series of) builds e.g.
How to Map Versions to Expo
version
maps toCFBundleVersion
(iOS) andversionName
(Android).ios.buildNumber
maps toCFBundleShortVersionString
(iOS).android.versionCode
maps toversionCode
(Android).