Skip to main content

Overview

match is a new approach to iOS code signing: share one code signing identity across your development team to simplify your codesigning setup and prevent code signing issues.
match stores your certificates and profiles in a git repo, encrypted and synced across your team.

Why match?

The Problem

  • Every team member has their own code signing identity
  • Certificates and profiles expire randomly
  • Setting up new machines is complicated
  • Certificates often conflict between team members

The Solution

match creates one shared identity stored in a private git repository, encrypted with a passphrase.

Installation

match is part of fastlane. Install it with:
fastlane match

Quick Start

1

Create a git repository

Create a private git repository to store certificates.
# On GitHub, GitLab, or Bitbucket
# Make sure it's private!
2

Initialize match

fastlane match init
This creates a Matchfile with your git repo URL.
3

Generate certificates

fastlane match appstore
fastlane match development
This generates and encrypts certificates in your git repo.
4

Use on other machines

fastlane match appstore
match downloads and installs certificates automatically.

How match Works

1

Generate certificates

match generates certificates and provisioning profiles on the Apple Developer Portal.
2

Encrypt and store

Certificates are encrypted with a passphrase and committed to your git repository.
3

Install on team machines

Team members run match to download, decrypt, and install certificates in their keychain.

CLI Commands

fastlane match development

Certificate Types

development
string
Creates iOS/tvOS/macOS development certificates and profiles.
fastlane match development
adhoc
string
Creates ad-hoc distribution certificates and profiles.
fastlane match adhoc
appstore
string
Creates App Store distribution certificates and profiles.
fastlane match appstore
enterprise
string
Creates enterprise distribution certificates and profiles.
fastlane match enterprise
developer_id
string
Creates Developer ID certificates (macOS).
fastlane match developer_id

Key Options

git_url
string
URL to the git repo containing certificates.
match(
  type: "appstore",
  git_url: "https://github.com/company/certificates.git"
)
app_identifier
string/array
The bundle identifier(s) of your app.
match(
  type: "appstore",
  app_identifier: "com.example.app"
)
Or multiple:
match(
  type: "appstore",
  app_identifier: [
    "com.example.app",
    "com.example.app.watchkit"
  ]
)
type
string
default:"development"
Define the profile type (development, adhoc, appstore, enterprise).
match(type: "appstore")
username
string
Your Apple ID username.
match(username: "[email protected]")
team_id
string
The ID of your Developer Portal team.
match(team_id: "Q2CBPJ58CA")
readonly
boolean
default:"false"
Only fetch existing certificates, don’t generate new ones.
match(
  type: "appstore",
  readonly: true
)
force
boolean
default:"false"
Renew provisioning profiles every time.
match(
  type: "appstore",
  force: true
)
force_for_new_devices
boolean
default:"false"
Renew profiles when device count changes.
match(
  type: "development",
  force_for_new_devices: true
)
git_branch
string
default:"master"
Specific git branch to use.
match(
  type: "appstore",
  git_branch: "production"
)
git_basic_authorization
string
Use basic authorization to access the git repo.
match(
  type: "appstore",
  git_basic_authorization: ENV["GIT_TOKEN"]
)
keychain_name
string
default:"login.keychain"
Keychain to import certificates to.
match(
  type: "appstore",
  keychain_name: "fastlane.keychain"
)
keychain_password
string
Password for the keychain.
match(
  type: "appstore",
  keychain_name: "fastlane.keychain",
  keychain_password: ENV["KEYCHAIN_PASSWORD"]
)
platform
string
default:"ios"
Set the platform (ios, tvos, macos, catalyst).
match(
  type: "appstore",
  platform: "macos"
)
storage_mode
string
default:"git"
Storage backend (git, google_cloud, s3, gitlab_secure_files).
match(
  type: "appstore",
  storage_mode: "s3",
  s3_bucket: "my-certificates"
)

Using with fastlane

Basic Usage

lane :beta do
  match(type: "appstore")
  gym
  pilot
end

Development Build

lane :dev do
  match(type: "development")
  gym(export_method: "development")
end

Multiple App Identifiers

lane :release do
  match(
    type: "appstore",
    app_identifier: [
      "com.example.app",
      "com.example.app.watchkit",
      "com.example.app.watchkit.extension"
    ]
  )
  gym
  deliver
end

CI/CD Setup

lane :ci_build do
  create_keychain(
    name: "ci.keychain",
    password: ENV["KEYCHAIN_PASSWORD"],
    default_keychain: true,
    unlock: true,
    timeout: 3600
  )
  
  match(
    type: "appstore",
    readonly: true,
    keychain_name: "ci.keychain",
    keychain_password: ENV["KEYCHAIN_PASSWORD"]
  )
  
  gym
end

Storage Backends

Git (Default)

match(
  type: "appstore",
  git_url: "https://github.com/company/certificates.git",
  git_branch: "main"
)

Google Cloud Storage

match(
  type: "appstore",
  storage_mode: "google_cloud",
  google_cloud_bucket_name: "my-certificates",
  google_cloud_keys_file: "./gc_keys.json"
)

Amazon S3

match(
  type: "appstore",
  storage_mode: "s3",
  s3_bucket: "my-certificates",
  s3_region: "us-east-1"
)

GitLab Secure Files

match(
  type: "appstore",
  storage_mode: "gitlab_secure_files",
  gitlab_project: "gitlab-org/gitlab"
)

Matchfile

Create a Matchfile for persistent configuration:
# Matchfile

git_url "https://github.com/company/certificates.git"
git_branch "main"

type "appstore"

app_identifier [
  "com.example.app",
  "com.example.app.watchkit"
]

username "[email protected]"
team_id "Q2CBPJ58CA"

keychain_name "login.keychain"
Generate a template:
fastlane match init

Nuke Command

Destructive operation: The nuke command permanently deletes certificates from the Developer Portal.
Revoke and delete all certificates:
# Delete development certificates
fastlane match nuke development

# Delete distribution certificates
fastlane match nuke distribution

# Delete enterprise certificates
fastlane match nuke enterprise
Then regenerate:
fastlane match development
fastlane match appstore

Change Password

Re-encrypt all files with a new password:
fastlane match change_password

Environment Variables

MATCH_GIT_URL
string
URL to the git repo
MATCH_TYPE
string
Certificate type (development, adhoc, appstore)
MATCH_APP_IDENTIFIER
string
Bundle identifier
MATCH_USERNAME
string
Your Apple ID username
MATCH_KEYCHAIN_NAME
string
Keychain name
MATCH_KEYCHAIN_PASSWORD
string
Keychain password
MATCH_PASSWORD
string
Passphrase to decrypt certificates
MATCH_READONLY
boolean
Readonly mode

Tips & Best Practices

Use private repository: Always use a private git repository to store certificates.
Save your passphrase: Store the encryption passphrase in a secure password manager.
One identity per team: All team members share the same certificates - no more conflicts!
CI readonly mode: Use readonly: true on CI to prevent generating new certificates.

Troubleshooting

Certificate already exists

Use readonly mode to fetch existing certificates:
match(type: "appstore", readonly: true)

Wrong passphrase

The passphrase is the one you set when first running match. Store it securely:
export MATCH_PASSWORD="your-passphrase"

Device limit reached

Use nuke to clean up and regenerate:
fastlane match nuke development
fastlane match development

Git authentication failed

Use a personal access token:
match(
  type: "appstore",
  git_basic_authorization: Base64.strict_encode64("username:token")
)
  • cert - Alternative certificate management
  • sigh - Alternative provisioning profile management
  • gym - Build your app with match certificates
  • pilot - Upload to TestFlight

Build docs developers (and LLMs) love