skip to content

In Flutter, what do --build-name and --build-number override, and what build number ships when pubspec's version line has no + part?

level: middleimportance: should knowfreq 40%

answer

  1. flags beat the pubspec line
  2. CI run number as build number
  3. Android falls back to versionCode 1
  4. iOS falls back to the build name
  5. 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
bash
# 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=412

go deeper

for a junior

Recall that --build-name and --build-number override the two halves of the pubspec version for one build.

for a middle

Explain the fallbacks without a + part, Android versionCode 1 and iOS reusing the build name, and how each platform sanitises the number.

for a senior

Design the pipeline so both stores get one increasing build number from a single source, and catch silent sanitising and ABI offsets.

for a principal

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.