Marketing version versus build number
Every iOS app has two version identifiers. Both live in your Info.plist
(or the equivalent build settings in Xcode):
-
Marketing version — key
CFBundleShortVersionString. The user-facing version displayed on the App Store (1.12.0, 2.0.1). Must be three non-negative integers separated by dots. Must increase monotonically relative to the last approved version. -
Build number — key
CFBundleVersion. The internal build identifier. Any numeric or dotted-numeric value (1, 42, 1.12.0.14, 202604231015). Must be unique within a marketing version. Apple uses this to distinguish the N-th build of 1.12.0 from the N+1-th build.
A practical pattern: marketing version follows semver (1.12.0, 1.12.1, 2.0.0). Build
number is a monotonically increasing integer across the entire life of the app —
1, 2, 3, …, 847. Many teams use a CI counter or a date-based scheme
(YYYYMMDDhhmm). Do not reset the build number when you bump the
marketing version; keeping it monotonic across versions avoids confusion and makes
TestFlight build sorting cleaner.
App Store Connect's rules:
- Marketing version must be strictly greater than the previously approved version (version-sort order, not string compare).
- Build number must be unique per marketing version. You can re-use build number 1 when marketing version goes from 1.12.0 to 1.13.0, but it's cleaner not to.
- A build with a lower build number than one already uploaded for the same marketing version will be rejected on upload.
AppConsul's version and build number helper validates these rules against your current ASC state before you archive, avoiding the mid-upload rejection.
App Store Connect version states
A version moves through several named states between creation and going live. The core sequence:
| State | What it means | Actions available |
|---|---|---|
| Prepare for Submission | The draft state. Metadata is editable, build can be attached. | Edit, attach build, delete, submit. |
| Waiting for Review | Submitted, sitting in the review queue. | Cancel submission. No further edits. |
| In Review | A reviewer has started looking at the app. | Cancel submission (not recommended mid-review). |
| Pending Developer Release | Approved, waiting for you to tap Release. | Release This Version, or revert to Ready for Sale behavior on the next version. |
| Pending Apple Release | Approved, waiting for the scheduled release date you set. | Wait or release now. |
| Processing for App Store | Transitional state after release, usually a few minutes. | Wait. |
| Ready for Sale | Live on the App Store. | Remove from Sale, new version. |
| Rejected | App Review returned the version with issues. | Reply in Resolution Center or resubmit. |
| Metadata Rejected | Rejected for metadata only; you can fix metadata without a new build. | Edit metadata, resubmit. |
| Developer Rejected | You cancelled the submission. | Edit and resubmit when ready. |
| Removed from Sale | You or Apple removed the app from the Store. | Restore, new version. |
| Developer Removed from Sale | You removed it; it's not visible but data is retained. | Restore. |
The transitions you'll see most in a typical release are Prepare for Submission → Waiting for Review → In Review → Pending Developer Release (or Pending Apple Release) → Processing for App Store → Ready for Sale. AppConsul's version timeline renders these states as stage badges on each version row so the whole release history is visible at a glance.
Build upload and processing
After you archive in Xcode and distribute (or use xcrun altool, Transporter, Xcode
Cloud, Fastlane's pilot, or any other upload path), the build enters
the Processing stage in App Store Connect. During processing, Apple:
- Validates the binary structure and entitlements.
- Scans for private API usage and banned symbols.
- Extracts icons, metadata, and supported device/OS matrix.
- Strips debug symbols (unless you uploaded them) and generates the TestFlight-ready bundle.
Processing usually takes 5 to 30 minutes. The upper bound is an hour; if a build sits in Processing for more than an hour, re-upload a fresh build with a bumped build number. Apple occasionally has background processing delays that don't resolve without the re-upload.
You'll receive an email when processing completes (success or failure). Common
failure reasons: missing export compliance setting, missing required device
families, an ITMS-XXXXX error about unsupported architecture, or
an invalid entitlement for your provisioning profile.
A successfully processed build appears in the Build section of any version and in the TestFlight tab. A build can be attached to at most one App Store version at a time, but the same build can be used for both App Store submission and TestFlight distribution simultaneously.
TestFlight: internal and external testing
Internal testing
Internal testers are members of your App Store Connect team who have been added to an Internal Testers group. Limits: up to 100 internal testers per app. Builds are available to internal testers immediately after processing completes — no separate review. Internal testers can install via the TestFlight iOS app using the Apple ID associated with their team access.
Internal testing is the right surface for your developers, QA, and product managers. Anything outside your team should go through external testing.
External testing
External testers are anyone outside your team: customer beta, select users, friends and family, clients. Limits: up to 10,000 external testers per app across all groups. You invite via email (individual invites or a public TestFlight link that anyone with the link can use).
Key difference from internal: every build sent to external testers must pass Beta App Review first. The first Beta App Review for a new app is usually the longest (typically under 24 hours). Subsequent builds of the same app, with incremental changes, often clear review within a few hours. Beta App Review is less strict than full App Review but still enforces the core guidelines (crashes, misleading functionality, illegal content). Once a build passes Beta App Review, subsequent builds within the same marketing version can often be distributed without re-review unless Apple flags something.
Public TestFlight links let anyone with the link join. You can cap participation, and you can revoke the link at any time. Public links are the best-fit pattern for beta programs that want low friction.
Build expiration
TestFlight builds expire 90 days after upload. Expired builds remain in App Store Connect but can't be installed by testers. If a build is approved by App Review and shipped to the App Store, the App Store copy is unaffected by TestFlight expiration — only the TestFlight distribution stops.
Practical implication: if you run a long-running beta, plan to ship a fresh build at least every 90 days to keep testers on a valid build. Many CI pipelines automatically upload a TestFlight build on every merge to main for exactly this reason.
Phased release: the 7-day ramp
Phased release is a toggle in the Version Release section of App Store Connect. When enabled for an approved version, the version rolls out to existing iOS users (those who already have the app installed) on a 7-day schedule:
- Day 1: approximately 1%
- Day 2: approximately 2%
- Day 3: approximately 5%
- Day 4: approximately 10%
- Day 5: approximately 20%
- Day 6: approximately 50%
- Day 7: 100%
Critical nuance: phased release only affects automatic updates for existing users. New installs from the App Store always get the latest approved version. Users who manually tap Update in the App Store also get the latest version regardless of phase.
Controls available during phased release: Pause (hold at the current percentage), Resume, and Release to All Users Now. If a crash spike or critical bug appears in Crashlytics or App Store Connect analytics during the ramp, pause, ship a fix, and resume.
Most teams enable phased release on every version as insurance. The downside is trivially small (slower rollout to existing users) and the upside is large (limits the blast radius of a bad release).
Manual versus automatic release
When Apple approves a version, it goes to one of four destinations depending on what you selected in the Version Release section:
- Automatically release this version — goes to Ready for Sale immediately after approval.
- Automatically release this version after App Review approval, with phased release — same, but starts the 7-day ramp.
- Manually release this version — sits in Pending Developer Release after approval. You tap Release This Version when ready.
- Automatically release this version at a specific date and time — sits in Pending Apple Release until the scheduled moment. You cannot set a date earlier than the approval time plus Apple's processing buffer.
Manual release is the safest default for coordinated launches — product launches tied to marketing events, simultaneous cross-platform releases, or releases where you want to confirm App Review's changes before going live.
"Hot patches" via TestFlight
If you ship a bad release and need to triage before Apple approves a full fix, you can distribute an urgent build via TestFlight internal testing (no review needed) to give your team and key affected users access to a patched version while you push the real fix through App Review. It's not a true hot patch — the public App Store users remain on the bad version — but it buys time.
For public users, your options are: submit the fix as a new version with an expedited review request, or use phased release controls on a future version to limit exposure.
Version skipping and bumping rules
You don't have to ship every semver increment. Skipping is allowed:
- 1.12.0 → 1.14.0 (skip 1.13) — allowed.
- 1.12.0 → 2.0.0 — allowed, common after redesigns.
- 1.12.0 → 1.11.5 — not allowed; marketing version must increase.
- 1.12.0 → 1.12.0 — not allowed; you cannot reuse an approved marketing version.
You can, however, create a new version on App Store Connect that reuses a pending marketing version string as long as it hasn't been approved yet.
Common errors and how to fix them
- ITMS-90562: Invalid Bundle — usually a malformed entitlements file or a missing signature. Re-sign with a valid provisioning profile.
- ITMS-90286: Invalid Code Signing Entitlements — the entitlements in the build don't match the provisioning profile. Regenerate the profile in the Developer portal.
- "This build is no longer available" in TestFlight — the 90-day expiration hit. Upload a new build.
- "A newer build is already in review" — you can't have two versions in review simultaneously. Cancel or wait.
- Version stuck in Processing for hours — Apple's processing pipeline hung. Bump the build number and re-upload.
Frequently asked questions
Marketing version vs build number?
Marketing version (CFBundleShortVersionString) is the public 1.12.0 value. Build number (CFBundleVersion) is the internal identifier, unique per marketing version.
How long does TestFlight build processing take?
Typically 5-30 minutes, up to an hour. Re-upload if it's stuck longer.
How long do TestFlight builds last?
90 days from upload. After expiration the App Store Connect listing remains but testers can't install.
Internal vs external testing?
Internal: up to 100 team members, no review, instant. External: up to 10,000 testers, Beta App Review required for each build.
What does phased release do?
Ramps a new version to existing auto-updating users over 7 days (~1%, 2%, 5%, 10%, 20%, 50%, 100%). New installs always get the latest version regardless.
Can I skip a version?
Yes. Go from 1.12.0 to 1.14.0 or 2.0.0. You cannot go backwards or reuse an approved version.
What does Pending Developer Release mean?
Approved by Apple, waiting for you to tap Release because you chose Manually Release.
Every version on one timeline.
AppConsul's versions view renders the full history with stage badges (Prepare, Submitted, In Review, Pending Developer Release, Ready for Sale) and surfaces macOS notifications when Apple moves a version to the next state.
See AppConsul →