Overview
xcodebuild is Apple’s command-line tool for building, testing, and archiving Xcode projects and workspaces. It is the backbone of iOS, macOS, watchOS, and tvOS build automation, used extensively in CI/CD pipelines, scripts, and anywhere Xcode’s GUI is not available or desired. xcodebuild performs the same compilation, linking, code signing, and packaging operations as building from within Xcode, but exposes these operations through command-line flags and arguments.
The tool supports building projects (.xcodeproj) and workspaces (.xcworkspace), running unit and UI tests on simulators and real devices, creating archives for distribution, and exporting signed IPA files. It integrates with xcpretty for human-readable output, xctestrun files for test distribution, and Apple’s notarization service for macOS app distribution. xcodebuild is essential for any team automating their Apple platform builds.
Installation
# xcodebuild comes with Xcode Command Line Tools
xcode-select --install
# Verify installation
xcodebuild -version
# List available SDKs
xcodebuild -showsdks
# List installed simulators
xcrun simctl list devices available
# Switch Xcode version (if multiple installed)
sudo xcode-select -s /Applications/Xcode-16.app/Contents/Developer
xcode-select -p # Print current developer directory
# Accept Xcode license
sudo xcodebuild -license accept
# Install additional components
xcodebuild -runFirstLaunch
Basic Build Commands
# Build project
xcodebuild -project MyApp.xcodeproj \
-scheme MyApp \
-configuration Debug \
-sdk iphonesimulator \
build
# Build workspace (CocoaPods/SPM)
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
-configuration Debug \
-sdk iphonesimulator \
build
# Build for specific destination
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=17.4' \
build
# Build with derived data path
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
-derivedDataPath ./build \
build
# Clean build
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
clean build
# Build only (no link)
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
build-for-testing
Common Flags
| Flag | Description |
|---|
-project | Path to .xcodeproj |
-workspace | Path to .xcworkspace |
-scheme | Build scheme name |
-configuration | Debug or Release |
-sdk | Target SDK (iphoneos, iphonesimulator, macosx) |
-destination | Build/test destination device |
-derivedDataPath | Custom derived data output |
-arch | Architecture (arm64, x86_64) |
-jobs | Number of parallel build jobs |
-quiet | Suppress build output |
-verbose | Detailed build output |
-allowProvisioningUpdates | Auto-update provisioning |
-resultBundlePath | Output result bundle |
-showBuildSettings | Print all build settings |
-list | List schemes and targets |
Testing
# Run unit tests
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=17.4' \
-resultBundlePath ./test-results
# Run specific test class
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-only-testing:MyAppTests/LoginTests
# Run specific test method
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-only-testing:MyAppTests/LoginTests/testSuccessfulLogin
# Skip specific tests
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-skip-testing:MyAppTests/SlowTests
# Build for testing (without running)
xcodebuild build-for-testing \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-derivedDataPath ./build
# Run pre-built tests
xcodebuild test-without-building \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-derivedDataPath ./build
# Parallel testing on multiple simulators
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-parallel-testing-enabled YES \
-maximum-concurrent-test-simulator-destinations 2
# Test with code coverage
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-enableCodeCoverage YES
# Extract coverage report
xcrun xccov view --report ./test-results.xcresult
Archiving and Exporting
# Create archive
xcodebuild archive \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-configuration Release \
-archivePath ./build/MyApp.xcarchive \
-allowProvisioningUpdates \
CODE_SIGN_IDENTITY="Apple Distribution" \
DEVELOPMENT_TEAM="ABCDEF1234"
# Export IPA from archive
xcodebuild -exportArchive \
-archivePath ./build/MyApp.xcarchive \
-exportPath ./build/export \
-exportOptionsPlist ExportOptions.plist
# Export for App Store
xcodebuild -exportArchive \
-archivePath ./build/MyApp.xcarchive \
-exportPath ./build/appstore \
-exportOptionsPlist AppStoreExportOptions.plist
<!-- ExportOptions.plist (Ad Hoc) -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>ad-hoc</string>
<key>teamID</key>
<string>ABCDEF1234</string>
<key>signingStyle</key>
<string>automatic</string>
<key>thinning</key>
<string><none></string>
<key>compileBitcode</key>
<false/>
</dict>
</plist>
<!-- AppStoreExportOptions.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>ABCDEF1234</string>
<key>signingStyle</key>
<string>automatic</string>
<key>uploadSymbols</key>
<true/>
<key>uploadBitcode</key>
<false/>
</dict>
</plist>
Simulator Management
# List all simulators
xcrun simctl list devices
# Create simulator
xcrun simctl create "Test iPhone" "iPhone 15 Pro" "iOS17.4"
# Boot simulator
xcrun simctl boot "iPhone 15 Pro"
# Shutdown simulator
xcrun simctl shutdown "iPhone 15 Pro"
xcrun simctl shutdown all
# Erase simulator
xcrun simctl erase "iPhone 15 Pro"
xcrun simctl erase all
# Install app on simulator
xcrun simctl install "iPhone 15 Pro" ./build/MyApp.app
# Launch app
xcrun simctl launch "iPhone 15 Pro" com.example.myapp
# Take screenshot
xcrun simctl io "iPhone 15 Pro" screenshot screenshot.png
# Record video
xcrun simctl io "iPhone 15 Pro" recordVideo recording.mp4
# Set device location
xcrun simctl location "iPhone 15 Pro" set 37.7749,-122.4194
# Open URL in simulator
xcrun simctl openurl "iPhone 15 Pro" "myapp://deeplink"
# Send push notification
xcrun simctl push "iPhone 15 Pro" com.example.myapp notification.json
Build Settings
# View all build settings
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
-showBuildSettings
# Override build settings
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
PRODUCT_BUNDLE_IDENTIFIER=com.example.myapp \
MARKETING_VERSION=2.0.0 \
CURRENT_PROJECT_VERSION=42 \
CODE_SIGN_IDENTITY="Apple Development" \
DEVELOPMENT_TEAM=ABCDEF1234 \
PROVISIONING_PROFILE_SPECIFIER="MyApp Dev" \
build
| Setting | Description |
|---|
PRODUCT_BUNDLE_IDENTIFIER | App bundle ID |
MARKETING_VERSION | User-visible version (CFBundleShortVersionString) |
CURRENT_PROJECT_VERSION | Build number (CFBundleVersion) |
CODE_SIGN_IDENTITY | Signing certificate name |
DEVELOPMENT_TEAM | Apple Developer team ID |
PROVISIONING_PROFILE_SPECIFIER | Provisioning profile name |
SWIFT_OPTIMIZATION_LEVEL | Swift optimization (-Onone, -O, -Osize) |
GCC_OPTIMIZATION_LEVEL | C/ObjC optimization (0, s, 2, 3) |
Configuration
# xcpretty for readable output
gem install xcpretty
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
build 2>&1 | xcpretty
# With test report
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
2>&1 | xcpretty --report html --output ./test-report.html
# JSON report
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
2>&1 | xcpretty --report json-compilation-database
Advanced Usage
# Resolve Swift Package Manager dependencies
xcodebuild -resolvePackageDependencies \
-workspace MyApp.xcworkspace \
-scheme MyApp
# Build for multiple destinations (universal)
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp \
-destination 'generic/platform=iOS' \
ONLY_ACTIVE_ARCH=NO \
build
# Create XCFramework from archive
# Build for device
xcodebuild archive \
-scheme MyFramework \
-destination "generic/platform=iOS" \
-archivePath build/MyFramework-iOS \
SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# Build for simulator
xcodebuild archive \
-scheme MyFramework \
-destination "generic/platform=iOS Simulator" \
-archivePath build/MyFramework-Sim \
SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
# Create XCFramework
xcodebuild -create-xcframework \
-framework build/MyFramework-iOS.xcarchive/Products/Library/Frameworks/MyFramework.framework \
-framework build/MyFramework-Sim.xcarchive/Products/Library/Frameworks/MyFramework.framework \
-output build/MyFramework.xcframework
# Notarize macOS app
xcrun notarytool submit MyApp.zip \
--apple-id "developer@example.com" \
--team-id "ABCDEF1234" \
--password "@keychain:AC_PASSWORD" \
--wait
xcrun stapler staple MyApp.app
# Upload to App Store Connect
xcrun altool --upload-app \
--type ios \
--file MyApp.ipa \
--apiKey "KEY_ID" \
--apiIssuer "ISSUER_ID"
CI/CD Script Example
#!/bin/bash
set -euo pipefail
SCHEME="MyApp"
WORKSPACE="MyApp.xcworkspace"
ARCHIVE_PATH="./build/MyApp.xcarchive"
EXPORT_PATH="./build/export"
echo "==> Resolving dependencies"
xcodebuild -resolvePackageDependencies \
-workspace "$WORKSPACE" \
-scheme "$SCHEME"
echo "==> Running tests"
xcodebuild test \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
-resultBundlePath ./test-results \
2>&1 | xcpretty
echo "==> Creating archive"
xcodebuild archive \
-workspace "$WORKSPACE" \
-scheme "$SCHEME" \
-configuration Release \
-archivePath "$ARCHIVE_PATH" \
-allowProvisioningUpdates \
2>&1 | xcpretty
echo "==> Exporting IPA"
xcodebuild -exportArchive \
-archivePath "$ARCHIVE_PATH" \
-exportPath "$EXPORT_PATH" \
-exportOptionsPlist ExportOptions.plist \
2>&1 | xcpretty
echo "==> Build complete: $EXPORT_PATH"
Troubleshooting
| Issue | Solution |
|---|
| ”No scheme found” | Run xcodebuild -list to see available schemes; check shared scheme |
| Code signing error | Verify team ID, certificate, and provisioning profile; use -allowProvisioningUpdates |
| ”SDK not found” | Run xcodebuild -showsdks; ensure correct Xcode is selected |
| Simulator boot fails | Reset simulator: xcrun simctl erase all; check disk space |
| Tests timeout | Increase test timeout; check for blocking main thread |
| Archive fails | Ensure Release configuration builds; check signing config |
| SPM resolution fails | Delete Package.resolved; clear derived data |
| Build too slow | Use derived data caching; enable parallel builds with -jobs |
| ”Command line tools not found” | Run xcode-select --install or xcode-select -s |
| xcpretty hiding errors | Check raw output without xcpretty; use -verbose flag |