- Khalid Alaoui, iOS developer
- Release pipeline
Hundreds of apps, one command
iOS CI/CD for hundreds of apps: Fastlane, GitHub Actions on a self-hosted Mac mini, Match code signing and the App Store Connect API, so a release to every app is one command.
0 → 333merchant configurations on template 3.2.04 between 31 Jul and 31 Aug 2026
290 / 290live apps now on the same release
555 / 557commits since the pipeline landed (27 Mar 2026) are mine
One command.
Every app.
0of live apps released
An illustration of one run, drawn with the real list of live apps from merchants.json. The command is the real one.
The problem
Branding was injected into the project at build time by a git hook and a target-generator package, and there was no Fastlane or CI release pipeline.
With hundreds of apps, every template update meant a lot of manual work.
What I did
- 01Made
merchants.jsonthe single source of truth and generated one xcconfig per merchant from it. - 02Wrote
switch.shto stage icons, splash screens and Firebase config into gitignored paths, and removed the generator package. - 03Built Fastlane and GitHub Actions on a self-hosted Mac mini, with Match signing, build numbers read from App Store Connect and version-based detection of outdated apps.
- 04Parallel builds, each in its own git worktree. A pre-commit hook blocks leaked keys and webhooks.
What it looks like to use
# work on one restaurant locally $ ./scripts/switch.sh bagel # what would a release touch? $ ./scripts/update_merchants.sh --dry-run # ship every outdated app, four at a time $ ./scripts/update_merchants.sh --concurrency 4 # a brand-new client, registered in App Store Connect $ ./scripts/create_merchant.sh newslug
Need an iOS
developer?
[email protected] →Freelance projects, or a full-time role, remote or with relocation. Résumé (PDF)