Xcode Cloud signs builds for you with Apple-managed certificates and profiles. That is genuinely convenient, until the day you want to run the same release from another CI, from fastlane, or from a laptop, and discover the signing identity is locked inside Xcode Cloud. Migrating means owning your signing material again: keep it in the HexSign vault, and fetch it with the hexsign CLI from whatever CI you move to. For a feature-by-feature breakdown, see HexSign vs Xcode Cloud.
Why teams move off Xcode Cloud
- Portability: the same certificate and profile have to work in GitHub Actions, GitLab, CircleCI, Bitrise, Jenkins, fastlane, and a local release, not just inside Apple's runners.
- Cost: Xcode Cloud bills by compute minute, which adds up next to CI minutes you already pay for.
- Visibility: managed signing is opaque, so it is hard to answer which certificate signed a given build, or when it expires.
- Consolidation: most teams want one place that holds signing material and one pattern for every pipeline, instead of one special case for Xcode Cloud.
What changes, and what doesn't
- Stays the same
- Your
xcodebuild archiveand export steps, your scheme, and the certificate and profile themselves. You are changing where signing material comes from, not how Xcode builds. - Changes
- Signing material moves from Apple-managed storage into the HexSign vault, and a fetch step (the CLI, an action, an orb, a Step, or a component) runs before the build to pull it onto the runner.
Step 1: get your signing material into HexSign
Connect your Apple account and HexSign syncs your existing certificates and provisioning profiles through the App Store Connect API. For a certificate HexSign didn't issue, the synced record arrives without a private key, so upload the matching .p12 key to enable signing. Prefer a clean start? Generate a fresh certificate and HexSign holds the key from the outset. Either way, HexSign tracks expiration and handles renewals, which is the piece Xcode Cloud used to own.
Step 2: pick a target CI
Choose where the build will run. Every destination uses the same fetch-then-build pattern, with a thin wrapper per platform: the GitHub Actions, GitLab CI/CD, CircleCI, Bitrise, and Jenkins pages each show the exact configuration, and the fastlane plugin does the same from inside a lane.
Step 3: recreate the archive step
Wherever you land, the build step is the same three commands. Store the service credential as CI secrets, fetch the certificate and profile, then archive exactly as before:
# Runs in any CI with a macOS shell. # Auth: set HEXSIGN_CLIENT_ID and HEXSIGN_CLIENT_SECRET as CI secrets. hexsign certificates download "$HEXSIGN_CERT_ID" \ --output-dir build/sign --keychain "$RUNNER_TEMP/signing.keychain-db" hexsign profiles download "$HEXSIGN_PROFILE_ID" \ --output-dir build/sign --install xcrun xcodebuild archive \ -workspace MyApp.xcworkspace \ -scheme MyApp \ -archivePath build/MyApp.xcarchive
--keychain creates a dedicated keychain, imports the .p12, and runs the set-key-partition-list authorization codesign needs. --install drops the profile where Xcode finds it. Because you control signing now, the export step uses a manual signing style with your profile rather than Xcode Cloud's automatic flow.