In a Flutter pubspec.yaml, what does version: 1.2.3+4 become in the Android and iOS builds?
answer
- one line feeds both stores
- before + is the build name
- after + is the build number
- versionName and versionCode
- CFBundleShortVersionString and CFBundleVersion
basics
~10 sThe part before + (1.2.3) is the build name, used as Android versionName and iOS CFBundleShortVersionString; the part after + (4) is the build number, used as Android versionCode and iOS CFBundleVersion.
solid answer
~30 sFlutter splits the `version` line on `+`. The **build name** `1.2.3` is the version users see: Android `versionName`, iOS `CFBundleShortVersionString`. The **build number** `4` is the internal, ever-increasing identifier: Android `versionCode`, iOS `CFBundleVersion`. The tool wires them in on every build: on Android it writes `flutter.versionName` and `flutter.versionCode` to `android/local.properties`, which the app's `build.gradle.kts` reads as `flutter.versionName` and `flutter.versionCode`; on iOS it writes `FLUTTER_BUILD_NAME` and `FLUTTER_BUILD_NUMBER` into `ios/Flutter/Generated.xcconfig`, which `Info.plist` references. So you change the version in `pubspec.yaml`, not in Gradle or Xcode.
code
yaml · 3 lines# pubspec.yaml
name: stadium_odds
version: 1.2.3+4go deeper
Recall the split: before + is the build name for users, after + is the build number stores compare, and the four native names each maps to.
Explain how the tool injects the values: local.properties for Gradle and Generated.xcconfig for Xcode, and why native edits get overwritten.
Set a numbering policy that keeps build numbers unique and increasing across both stores, including rebuilt uploads of the same build name.
Decide who owns version numbers across platforms and whether they are hand-edited or derived, and how that choice affects traceability from a crash to a commit.
## One line, two numbers Every app store tracks two different values for a release: - a **version name** people read in the store listing, such as `1.2.3`; - a **build number** the store uses to order uploads and reject duplicates, such as `4`. A Flutter app declares both on a single line of `pubspec.yaml`: ```yaml version: 1.2.3+4 ``` The Flutter tool parses the value as a version, then splits it on `+`: everything before is the **build name**, everything after is the **build number**. The build number is optional; what happens without it is a separate trap. ## Where each part lands | pubspec part | Flutter's term | Android | iOS | |---|---|---|---| | `1.2.3` | build name | `versionName` | `CFBundleShortVersionString` | | `4` | build number | `versionCode` | `CFBundleVersion` | The tool's own help for `--build-name` and `--build-number` spells out this mapping, and adds that on Windows the build name fills the major, minor and patch parts of the product version and the build number the build suffix. ## How the values get into the native projects The values are not copied by hand; the tool injects them on each build. 1. **Android.** The tool writes `flutter.versionName` and `flutter.versionCode` into `android/local.properties`. The Flutter Gradle plugin reads them, and the template's `android/app/build.gradle.kts` sets `versionCode = flutter.versionCode` and `versionName = flutter.versionName` inside `defaultConfig`. 2. **iOS.** The tool writes `FLUTTER_BUILD_NAME` and `FLUTTER_BUILD_NUMBER` into `ios/Flutter/Generated.xcconfig`. The template's `ios/Runner/Info.plist` sets `CFBundleShortVersionString` to `$(FLUTTER_BUILD_NAME)` and `CFBundleVersion` to `$(FLUTTER_BUILD_NUMBER)`. That is why editing `versionCode` in Gradle or the Version field in Xcode seems to work once and then gets overwritten: the pubspec line is the source of truth. You can hard-code values in the native files, but then the pubspec line silently stops mattering for that platform. ## Why the build number matters more than it looks - Both stores require the build number to be **unique** for an upload, and Google Play requires `versionCode` to **increase**. - The build name is free-form for users; the build number is what the store compares. - One build name can ship several build numbers: `1.2.3+4`, then `1.2.3+5` after a rejected upload. ## A worked example A team ships its first store release as `version: 1.0.0+1`. A crash fix goes out as `1.0.1+2`; the next feature release as `1.1.0+3`. When App Store Connect rejects `1.1.0+3` for a metadata problem and the binary must be rebuilt, the team uploads `1.1.0+4`: same build name for users, new build number for the store. Nothing in Gradle or Xcode was touched. ## How other targets and tools see the same values The same pair of values reaches more than the two mobile stores: - **Desktop.** On Windows the build name fills the major, minor and patch parts of the product and file versions, and the build number fills the build suffix, as the tool's help for the flags states. macOS uses the same `CFBundleShortVersionString` and `CFBundleVersion` pair as iOS. - **Crash reports.** Crash tooling on both platforms reports the native version values, so a report shows `1.2.3 (4)`, not the pubspec line. Keeping the build number identical on Android and iOS for one release means one number identifies one code state everywhere. - **Dart code.** The version is not a Dart constant. Showing it on an About screen needs a plugin that reads the native values at runtime, or a value passed in at build time; reading `pubspec.yaml` at runtime is not possible because the file is not bundled. In every case the rule is the same: change the line in `pubspec.yaml`, or pass the override flags, and let the tool propagate it. ## Common mistakes - Treating `+4` as a pre-release or metadata tag and leaving it at `+1` forever; the stores then reject the second upload. - Editing the version in Gradle or Xcode and wondering why the next `flutter build` puts the old value back. - Assuming the same number means the same thing everywhere: users see only the build name; the build number is for the store. - Writing a two-part version such as `1.2`; the tool prints a hint that the value is invalid and ignores it, so the defaults apply.
- Why does changing versionCode in build.gradle.kts not stick in a Flutter project?The template sets `versionCode = flutter.versionCode`, which the Flutter Gradle plugin reads from `android/local.properties`. The tool rewrites that file from `pubspec.yaml` on every build, so the pubspec line wins unless you replace the expression with a literal.
- Which of the two values does a store use to decide whether an upload is newer?The build number: `versionCode` on Android and `CFBundleVersion` on iOS. The build name is what users read, and stores do not use it to order uploads.
The build name is the edition printed on a book's cover; the build number is the print-run number on the copyright page. Readers only see the edition, while the warehouse refuses a second print run with the same number.
saying these in an interview costs you the question
- The number after + is SemVer build metadata that the stores ignore.
- The version must be edited separately in build.gradle.kts and Xcode.
- The build name is used as versionCode on Android.
- CFBundleShortVersionString holds the build number on iOS.
- Users see the build number in the store listing.