xcodebuild is the command-line interface to Xcode's build system. Everything the Xcode GUI does when you press Product > Archive, xcodebuild does from a terminal: compile, run tests, produce an .xcarchive, and export a signed .ipa. If a build runs on a CI machine, xcodebuild is the tool doing the work, whether you call it directly or through fastlane, which wraps it.
The archive and export flow
Shipping a build from the command line is two invocations. The first compiles and signs the app into an archive. The second re-signs and packages it for a specific distribution method, driven by an exportOptions.plist file.
# 1. Build and archive xcodebuild archive \ -scheme MyApp \ -configuration Release \ -archivePath build/MyApp.xcarchive # 2. Export a signed .ipa from the archive xcodebuild -exportArchive \ -archivePath build/MyApp.xcarchive \ -exportOptionsPlist ExportOptions.plist \ -exportPath build/
The signing flags that matter
- CODE_SIGN_IDENTITY
- Which certificate signs the build, matched by name against the keychain (for example "Apple Distribution"). Usually left to the project settings rather than overridden on the command line.
- -allowProvisioningUpdates
- Lets xcodebuild talk to the Apple Developer portal to create or fix profiles during the build, the command-line counterpart of Xcode's automatic signing. On CI, pair it with -authenticationKeyPath and the related flags so it authenticates with an App Store Connect API key instead of an Apple ID.
- -exportOptionsPlist
- Path to the exportOptions.plist that tells -exportArchive which distribution method, team, and profiles to use.
- OTHER_CODE_SIGN_FLAGS="--keychain <path>"
- Points signing at a specific keychain. CI jobs create a temporary keychain, import the .p12 into it, and pass it here so builds never touch the login keychain.
Where the signing material comes from
xcodebuild does not fetch certificates or profiles by itself (unless -allowProvisioningUpdates is on). It signs with whatever is already present: certificates and private keys come from a macOS keychain, and provisioning profiles are read from ~/Library/Developer/Xcode/UserData/Provisioning Profiles (and, on newer Xcode versions, ~/Library/MobileDevice/Provisioning Profiles). CI setup is mostly the work of getting the right files into those two places before xcodebuild runs.