In fastlane's build_app, what does export_method decide about the resulting iOS .ipa?
answer
- the archive is channel-neutral
- the export is where signing commits
- app-store, ad-hoc, enterprise, development
- picks the profile type and entitlements
- wrong value is rejected at upload
basics
~10 sexport_method tells fastlane's build_app which Apple distribution channel the export is signed for - app-store, ad-hoc, enterprise or development - and that choice decides which provisioning profile and entitlements are baked into the .ipa.
solid answer
~40 s`build_app` archives once and exports once, and `export_method` governs the export. The `.xcarchive` is channel-neutral; the export step signs and repackages it for exactly one Apple distribution channel, so `export_method` decides which kind of provisioning profile Xcode looks for and which entitlements land inside the `.ipa`. `app-store` produces the package you hand to `upload_to_app_store` (`deliver`) or `upload_to_testflight` (`pilot`); `ad-hoc` produces one installable only on the devices listed in the profile — how field engineers get our lighthouse maintenance app onto their registered iPads; `enterprise` is in-house distribution under Apple's enterprise programme; `development` is a developer-signed build. Getting it wrong fails late: an ad-hoc `.ipa` is rejected on upload, and a store-signed one will not side-load. `export_options` carries the finer export-options keys around it.
go deeper
Learn the four values you will actually type - app-store, ad-hoc, enterprise, development - and that the choice decides where the resulting iOS build can be installed, not how fast it compiles.
Explain that the archive is channel-neutral and the export is where signing commits, so export_method selects the provisioning profile type and the entitlements written into the .ipa.
Diagnose from the symptom: rejected at upload means an ad-hoc or development export, will not install on a tester's device means a store export. Then name the option you would change and why.
Decide the policy: one archive re-exported per channel is cheaper and provably the same code, while a build per destination is easier to trace. State which you would standardise on and what evidence you keep.
## One archive, several possible exports `build_app` (alias `gym`) runs Apple's `xcodebuild` in two phases. The **archive** phase compiles your `scheme` under a `configuration` and writes an `.xcarchive` — a bundle holding the built iOS app and its debug-symbol dSYMs. The archive is deliberately **channel-neutral**: nothing in it commits to how the app will reach a device. The **export** phase is where that commitment happens. Xcode re-signs the app out of the archive and packages it as an `.ipa`, and `export_method` is the option that tells it which channel to sign for. Because a channel on Apple platforms *is* a signing decision — a certificate, a provisioning profile and a set of entitlements — `export_method` is not cosmetic. It changes the bytes you ship. ## The values and what each one is for | `export_method` | Signed for | Installs how | |---|---|---| | `app-store` | App Store Connect | Uploaded, then distributed by Apple (store or beta service) | | `ad-hoc` | A fixed device list in the profile | Direct install on those registered devices only | | `enterprise` | In-house distribution under Apple's enterprise programme | Direct install inside the organisation | | `development` | A development profile | Install on the team's development devices | For macOS targets there are further values such as `developer-id`. Xcode has carried more than one spelling for some of these across its releases, so confirm the accepted set against the Xcode you actually build with rather than pasting a value out of an old lane. The profile type has to match the method. A store profile carries **no device list**; an ad-hoc profile embeds specific device identifiers. Producing those profiles is `sync_code_signing` (`match`) territory — `build_app` only consumes what is already on the machine. ## What a mismatch looks like The failures are late and confusing, which is exactly why interviewers ask: - An `ad-hoc` export uploaded with `upload_to_app_store` (`deliver`) or `upload_to_testflight` (`pilot`) is **rejected at upload**, after a full build has already burned. - An `app-store` export handed to a field engineer **will not install** by direct side-load, because it is not signed for that. - An `enterprise` export is installable only under the organisation that holds that programme membership. - A `development` export reaches only devices on the development profile, so a "working" QA build silently excludes half the test fleet. For our lighthouse maintenance app that means two distinct exports from the same source: an `ad-hoc` build for the engineers' registered iPads, and an `app-store` build that serves both the beta upload and the release submission. ## `export_method` versus `export_options` `export_method` is the one key you almost always set, and fastlane promotes it to a first-class option. Underneath, Xcode's export step reads an **export-options property list**, and `export_options` is how you supply the rest of it — either as a path to a plist file or as an inline hash. The keys inside it are Xcode's, not fastlane's (`provisioningProfiles`, `signingStyle`, and others), so treat `xcodebuild -help` as the authority on the current set rather than memory. `export_team_id` names the Apple Developer team the export signs under, which matters on a machine with access to several. `export_xcargs` passes raw arguments to the export invocation only. ## Switches that are easy to confuse with it - `include_symbols` — whether symbols travel with the exported package. Not a channel choice. - `include_bitcode` — a real `build_app` option, but whether Apple's store wants bitcode is Apple's policy and it has changed over time; check current Apple guidance rather than inheriting a flag from an old lane. - `skip_codesigning` — archives unsigned. Useful for a compile-only check; it produces nothing distributable, so no `export_method` rescues it. - `codesigning_identity` — pins the signing certificate, a different axis from the channel. ## Choosing it in a lane 1. Decide the **destination** first: Apple's store or beta service, a known device list, or an in-house fleet. 2. Set `export_method` to the matching value, and make sure the profile the machine holds is of the same type. 3. Pin the profile explicitly through `export_options` rather than letting Xcode pick, whenever more than one candidate profile is installed. 4. Keep a separate lane per destination rather than one lane with a flag nobody can trace, so the export a given job produced is obvious from its name. The short version to say out loud: the archive is the master, `export_method` is the decision about what the print is for, and every downstream "invalid signature" on upload starts here.
- You need the same commit as both an ad-hoc QA build and a store build - do you archive twice?You do not have to. The `.xcarchive` is channel-neutral, so one archive can be exported twice with different `export_method` values, reusing `archive_path` with `skip_build_archive`. Many teams still archive twice for traceability, because each `build_app` run then has its own log, its own `.xcresult` and its own retained artifact.
- Which fastlane option carries the export-options keys that export_method does not cover?`export_options`. It takes either a path to an Xcode export-options property list or an inline hash, and it is where keys such as `provisioningProfiles` and `signingStyle` live. `export_team_id` sits alongside it for the Apple Developer team, and `export_xcargs` passes raw arguments to the export invocation only, not to the archive.
The .xcarchive is the photographic negative and the export is the print: one master, but a different print depending on whether it is going to the gallery, to a named list of friends, or to the publisher.
saying these in an interview costs you the question
- Thinks the archive itself is signed for a channel
- Believes an ad-hoc .ipa can be uploaded to App Store Connect
- Says a store-signed build can be side-loaded onto a test device
- Confuses export_method with the configuration such as Release
- Assumes any installed profile will do for any export method