In Flutter, what do --build-name and --build-number override, and what build number ships when pubspec's version line has no + part?
answer
- flags beat the pubspec line
- CI run number as build number
- Android falls back to versionCode 1
- iOS falls back to the build name
- non-digits are stripped
basics
~20 s--build-name and --build-number replace the two halves of pubspec's version for one build. Without a + part, Android's versionCode falls back to 1 and iOS's CFBundleVersion falls back to the build name, such as 1.2.3.
solid answer
~40 s`flutter build` accepts `--build-name=x.y.z` and `--build-number=N`, which take precedence over the halves of `pubspec.yaml`'s `version` for that build only; teams typically pass the CI run number as `--build-number` so every upload is unique without committing a pubspec change. If the version line has no `+`, there is no build number: on Android the tool removes `flutter.versionCode` from `local.properties` and the Flutter Gradle plugin falls back to `versionCode` 1, while on iOS the tool uses the build name, so `CFBundleVersion` becomes `1.2.3`. The tool also sanitises the number: Android keeps digits only with a minimum of 1, iOS keeps digits and dots. A second Android upload with versionCode 1 is then rejected.
code
bash · 3 lines# pubspec.yaml keeps: version: 3.8.0+1
flutter build appbundle --build-name=3.8.0 --build-number=412
flutter build ipa --build-name=3.8.0 --build-number=412go deeper
Recall that --build-name and --build-number override the two halves of the pubspec version for one build.
Explain the fallbacks without a + part, Android versionCode 1 and iOS reusing the build name, and how each platform sanitises the number.
Design the pipeline so both stores get one increasing build number from a single source, and catch silent sanitising and ABI offsets.
Choose where version authority lives, in the repository or in the pipeline, and how that choice supports rebuilds, hotfix branches and audits.
## The two flags The `flutter build` subcommands for mobile targets accept two options that replace the parts of the `version` line in `pubspec.yaml` for a single build: - **`--build-name=x.y.z`** — the user-visible version: Android `versionName`, iOS `CFBundleShortVersionString`. - **`--build-number=N`** — the internal identifier: Android `versionCode`, iOS `CFBundleVersion`. The tool's help says each build must have a unique identifier and higher numbers mean newer builds. The resolution order is simple: **flag first, pubspec second, platform default last**. ## Why pipelines use the flags Keeping `version: 1.4.0+1` in the repository and injecting the build number at build time avoids a commit for every upload: ```bash flutter build appbundle --build-number=$RUN_NUMBER flutter build ipa --build-number=$RUN_NUMBER ``` - The build name stays in `pubspec.yaml` where a human decides it. - The build number comes from something that only grows, such as a pipeline run counter. - Both stores receive the same number, which makes cross-platform crash reports easier to match. ## What happens without a + part The tool reads `buildNumber` from the pubspec only when the version contains `+`. Without one, there is no build number, and each platform falls back differently: | Platform | What the tool does | Resulting build number | |---|---|---| | Android | removes `flutter.versionCode` from `local.properties` | the Gradle plugin's default, `1` | | iOS | uses the build name for `FLUTTER_BUILD_NUMBER` | e.g. `1.2.3` | | iOS, no version at all | falls back to defaults | name `1.0.0`, number `1` | The asymmetry is the trap. The iOS build looks sensible because `CFBundleVersion` tracks the build name, but every Android build is `versionCode 1`, so Google Play rejects the second upload. ## Sanitising The tool rewrites invalid build numbers instead of failing, logging the change only at trace level: 1. **Android** strips every non-digit, parses the rest as an integer and raises anything below 1 to 1. `--build-number=2026.09.28` becomes `20260928`. 2. **iOS** keeps digits and dots, dropping empty segments, because `CFBundleVersion` allows dotted numbers. The same input stays `2026.09.28`. So one flag value can produce different-looking numbers on the two platforms, and a malformed value is silently changed rather than rejected. ## Split APKs and the ABI offset When APKs are split per ABI, the Flutter Gradle plugin rewrites each APK's `versionCode` to `ABI × 1000 + versionCode`, using 1 for 32-bit ARM, 2 for arm64 and 4 for x86_64, so the per-ABI APKs do not collide. The template comments that `-P force-version-code-ignoring-abi=true` disables that. App bundles are not split this way and keep the plain `versionCode`. ## A pipeline recipe A simple, deterministic scheme that avoids the traps above: 1. Keep the build name in `pubspec.yaml`, changed by a person when a release is planned, for example `version: 3.8.0+1`. 2. In the pipeline, compute one build number per commit that only grows, such as the run counter, and pass it to every platform build of that commit with `--build-number`. 3. Pass `--build-name` only when the pipeline, not the pubspec, owns the user-facing version; otherwise leave it out so the pubspec wins. 4. Record the pair, build name and build number, next to the artefacts so a crash report's version maps back to a commit. The result is a build number that is unique, increasing and identical in both stores, without a commit per upload and without depending on how either platform sanitises unusual values. ## Common mistakes - Dropping the `+` part to keep the version tidy, then hitting a duplicate `versionCode` on the second Play upload. - Using a timestamp with separators as the build number and being surprised that Android and iOS show it differently. - Passing `--build-number` on one platform's build only, so the two stores drift apart. - Committing a pubspec change for every build instead of injecting the build number at build time.
- What does flutter build do with --build-number=2026.09.28 on Android and on iOS?Android keeps only digits, giving `versionCode` 20260928. iOS keeps digits and dots, giving `CFBundleVersion` 2026.09.28. The tool rewrites the value rather than failing and logs the change only at trace level.
- Why might split-per-ABI APKs show versionCode 2004 when pubspec says +4?The Flutter Gradle plugin sets each split APK's `versionCode` to ABI × 1000 plus the build number, and arm64 is ABI 2. Passing `-P force-version-code-ignoring-abi=true` keeps the plain value.
saying these in an interview costs you the question
- --build-number permanently rewrites the version line in pubspec.yaml.
- Without a + part, the tool refuses to build.
- Without a + part, both platforms use the build name as the build number.
- An invalid --build-number value makes the build fail with an error.
- Android and iOS always show exactly the same build number string.