iOS

    Version vs build number on iOS: what's the difference?

    A 2026 Info.plist view showing CFBundleShortVersionString as the public version 1.2.0 and CFBundleVersion as the incrementing build number across successive App Store Connect uploads

    Two numbers describe every iOS app you upload, and mixing them up causes the most common rejection of all: "the bundle version must be higher than the previously uploaded version." One number is for your users, the other is for Apple's systems. The version is the public release number people see on the App Store; the build is the internal counter that has to climb with every upload. Here is exactly what each one is, the Info.plist keys behind them, and how they work together.

    Short answer

    On iOS, the version number is CFBundleShortVersionString, the user-facing release number like 1.2.0 that appears on the App Store and in Settings, and the build number is CFBundleVersion, an internal counter that identifies a specific build of that version. The key rule is that each binary you upload to App Store Connect for the same version must have a higher build number than the last, while the version number changes only when you ship a new release to users. So you might have version 1.2.0 with builds 1, 2, and 3 in TestFlight, then submit version 1.2.0 build 3 to the App Store.

    What you should know

    • Version is for users: CFBundleShortVersionString is the public release number, like 1.2.0.
    • Build is for uploads: CFBundleVersion identifies a specific binary of that version.
    • Build must increase: every upload for the same version needs a higher build number.
    • Version changes per release: you bump it when shipping a new version to users.
    • They are separate keys: both live in Info.plist and serve different purposes.

    What is the version number?

    The version number is the public, marketing-facing release number, stored in CFBundleShortVersionString. It is what users see on your App Store listing and in the iOS Settings app, and it typically follows semantic versioning, like 1.0.0 for launch, 1.1.0 for a feature update, and 1.0.1 for a bug fix. You change it when you release a new version of the app to the public, and the App Store treats a new version string as a new release that goes through App Review. So the version number communicates to users which release they have, and it should move in a way that makes sense as a product history, not on every internal build.

    What is the build number?

    The build number is the internal identifier for a specific build, stored in CFBundleVersion. It exists so Apple's systems and TestFlight can tell one upload of a version apart from another, and its defining rule is that it must increase with each upload for the same version string. It does not need to be user-friendly, so many teams use a simple incrementing integer or a date-based scheme. Users generally do not see the build number on the store, though it appears in TestFlight and crash reports. The build number is the value that causes the "bundle version must be higher" rejection when you forget to bump it before re-uploading.

    How they work together

    The version groups releases; the build counts the uploads within a release. The table shows a typical sequence.

    StageVersion (CFBundleShortVersionString)Build (CFBundleVersion)
    First TestFlight build1.2.01
    Fix, re-upload to TestFlight1.2.02
    Final build submitted to App Store1.2.03
    Next public release1.3.04

    The pattern is that the build number keeps climbing across everything you upload, while the version number only advances when you ship a new release to users. For a fix during testing, increment the build and keep the version the same, which also keeps you on the same Beta App Review train rather than starting a new one.

    What to watch out for

    The first trap is re-uploading without bumping the build number, which produces the "bundle version must be higher than the previously uploaded version" error; bump CFBundleVersion and re-archive. The second is bumping the version string for a small in-testing fix, which sends a new version's first build back through Beta App Review when a build bump would have stayed on the fast path. The third is losing track of which build you actually tested, since the build number is how you map a crash report or a security check back to a specific binary. A pre-submission scan such as PTKD.com (https://ptkd.com) reads the exact compiled IPA against OWASP MASVS, so noting the build number you scanned ties the result to the binary you submit, rather than to an earlier build that has since changed.

    What to take away

    • The version number, CFBundleShortVersionString, is the user-facing release like 1.2.0 shown on the App Store; the build number, CFBundleVersion, identifies a specific binary of that version.
    • Every upload for the same version must have a higher build number, while the version string changes only when you ship a new release.
    • For a fix during testing, increment the build and keep the version the same to avoid restarting Beta App Review.
    • Track the build number you test and scan, so a pre-submission scan such as PTKD.com maps to the exact binary you submit.
    • #version-number
    • #build-number
    • #cfbundleversion
    • #info-plist
    • #app-store-connect
    • #testflight
    • #ios

    Frequently asked questions

    What is the difference between version and build number on iOS?
    The version number, CFBundleShortVersionString, is the public release number like 1.2.0 that users see on the App Store and in Settings. The build number, CFBundleVersion, is an internal counter that identifies a specific build of that version. The version changes when you ship a new release; the build must increase with every upload of the same version. One is for users, the other is for Apple's systems and TestFlight.
    Why do I get 'the bundle version must be higher'?
    Because you re-uploaded a binary without increasing CFBundleVersion. Each upload to App Store Connect for the same version string must have a higher build number than the previous one. Bump the build number in your Info.plist or build settings, re-archive, and upload again. The version string can stay the same; it is the build number that must climb on every upload of that version.
    Do I need to change the version number for a TestFlight fix?
    No. For a fix during testing, increment the build number and keep the version string the same. Bumping the version string starts a new release, which sends its first build back through Beta App Review, while a build bump on the same version usually stays on the already-approved train. So change the build for iterative test builds, and reserve a version change for a release you intend to ship to users.
    Which number do users see on the App Store?
    The version number, CFBundleShortVersionString, such as 1.2.0. That is what appears on your App Store listing and in the iOS Settings app, and it typically follows semantic versioning. The build number generally is not shown to users on the store, though it appears in TestFlight and in crash reports, where it identifies exactly which build a tester installed or a crash came from.
    What format should each number use?
    The version number usually follows semantic versioning, like 1.0.0, 1.1.0, and 1.0.1, so it reads as a sensible product history to users. The build number only needs to increase per upload, so teams commonly use a simple incrementing integer or a date-based scheme. The build does not need to be user-friendly; it just has to be higher than the last build for the same version every time you upload.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free