Understanding code signing and provisioning in iOS
Learn how certificates, App IDs, entitlements, and provisioning profiles work together.
24 Jul 2026 · 8 min read
When building an iOS app, we eventually need to run it on a real device, send it to testers, or distribute it through the App Store.
For that to work, the app has to be signed. Code signing tells the system who created the app and helps ensure that the app has not been changed after it was signed. Provisioning tells the system what the app is allowed to do and where it is allowed to run.
Xcode can manage most of this automatically, but it helps to understand what happens behind the scenes, especially when working in larger teams, CI environments, or projects with stricter release processes.

The mental model
The code signing setup can be divided into three main parts:
App target- bundle identifier- entitlementsCertificate- signing identity- private keyProvisioning profile- App ID- allowed certificates- allowed entitlements- distribution type- devices, if needed
The app target defines what is being signed. The certificate identifies who signs it. The provisioning profile connects both sides by saying which App ID can be signed with which certificates, which entitlements are allowed, and where the app can run.
Signing works when these pieces match. If one of them is out of sync, Xcode cannot sign the app or iOS refuses to install it.
Certificates
A certificate identifies who is signing the app. It is issued by Apple and is connected to a private key stored in the keychain or managed by the signing system.
For iOS development, there are two common certificate categories:
- development certificates for running and debugging apps on devices
- distribution certificates for TestFlight, App Store, Ad Hoc, or other distribution workflows
When signing locally, the certificate alone is not enough. The machine also needs the matching private key. This is why copying only a certificate file to another Mac often does not fix signing problems. The private key has to be available too.
For many distribution workflows, Xcode can also use cloud-managed certificates. In that case, Apple manages the distribution certificate remotely and Xcode can sign through the Organizer distribution flow without requiring a local distribution certificate in the keychain.
App IDs
An App ID identifies the app in the Apple Developer account. It is connected to the app's bundle identifier, for example:
com.example.MyApp
The bundle identifier in Xcode has to match the App ID used for signing. If the app has extensions, each extension has its own bundle identifier and usually its own App ID as well.
The App ID is also where capabilities are enabled in the developer account. For example, if the app uses Push Notifications, Associated Domains, App Groups, iCloud, or Sign in with Apple, the App ID needs to support those capabilities.
Entitlements
Entitlements are values embedded into the signed app. They describe which protected capabilities the app wants to use.
In Xcode, we usually configure them in the Signing & Capabilities tab. Xcode then stores them in an .entitlements file and includes them when signing the app.
For example, an app using Associated Domains might include an entitlement like this:
<key>com.apple.developer.associated-domains</key><array><string>applinks:example.com</string></array>
The important detail is that entitlements have to match the provisioning profile. If an entitlement is present in the app but not allowed by the profile, signing or installation can fail.
Provisioning profiles
A provisioning profile is the file that ties everything together. It says:
- which App ID the app uses
- which certificates are allowed to sign it
- which entitlements are allowed
- which distribution method it is for
- which devices it can run on, if the profile is device-based
Provisioning profiles use the .mobileprovision file extension for iOS apps.
There are different profile types depending on what we want to do:
- development profiles are used for running and debugging on devices
- Ad Hoc profiles are used for distributing to registered devices
- App Store profiles are used for App Store and TestFlight distribution
Development and Ad Hoc profiles include devices. App Store profiles do not, because App Store distribution is not limited to specific registered test devices.
Automatic signing
With automatic signing, Xcode creates and updates signing assets for us. We select a team in the Signing & Capabilities tab, enable Automatically manage signing, and Xcode handles the required App IDs, certificates, and provisioning profiles when possible.
This is usually the most convenient setup for local development. It is also a good default when the project is not doing anything unusual.
Automatic signing becomes especially helpful when adding capabilities. If we add a capability in Xcode, Xcode can update the App ID and provisioning profile so the app's entitlements continue to match the profile.
Manual signing
With manual signing, we create and select the signing assets ourselves. This means choosing the provisioning profile and certificate for each relevant target and build configuration.
Manual signing can be useful when:
- a CI system needs predictable signing assets
- a team wants tighter control over profiles and certificates
- different configurations use different bundle identifiers
- the app has multiple targets or extensions with separate provisioning needs
Manual signing also means we are responsible for keeping profiles up to date. If we add a capability, register a new device, or change the App ID, the provisioning profile may need to be regenerated and downloaded again.
How Xcode signs the app
When Xcode signs an app, it combines the build product with the selected signing identity and provisioning profile.
For the signing step to succeed, the important values have to match:
- the app's bundle identifier has to match the App ID in the provisioning profile
- the certificate has to be included in the provisioning profile
- the app's entitlements have to be allowed by the provisioning profile
- the profile type has to match the build or distribution workflow
If the app contains extensions, the same applies to each extension target. The app target and every extension target need their own matching signing setup.
Common signing problems
Many signing errors come from one of a few mismatches.
If Xcode says that a provisioning profile does not include a signing certificate, the selected certificate is not part of that profile. This can happen after regenerating certificates or switching machines.
If Xcode says that a capability is not supported by the provisioning profile, the App ID or profile does not include the entitlement used by the app. Regenerating the profile after enabling the capability usually fixes this.
If an app installs on one device but not another, the development or Ad Hoc profile may not include the second device. In that case, the device needs to be registered and the profile needs to be updated.
If CI fails while local builds work, the CI environment may be missing the private key, the provisioning profile, or access to automatic signing. In that case, either the signing assets need to be installed in CI, or the CI workflow needs permission to manage signing through Xcode or App Store Connect.
Summary
Code signing and provisioning are easier to reason about when we separate the responsibilities.
A certificate identifies who signs the app. An App ID identifies the app. Entitlements describe what the app wants to do. A provisioning profile connects those pieces and defines where the signed app can run.
Automatic signing lets Xcode manage most of this for us. Manual signing gives us more control, but also makes us responsible for keeping certificates, profiles, entitlements, bundle identifiers, and devices in sync.



Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips



