{
"$type": "site.standard.document",
"description": "How I use XcodeGen to generate Xcode projects from project.yml, avoid Xcode project merge conflicts, and handle Package.resolved with SwiftPM.",
"path": "/i-finally-adopted-xcodegen-across-my-projects/",
"publishedAt": "2024-06-02T10:28:00.000Z",
"site": "at://did:plc:bryys25pc2fnagnyxqgsglhd/site.standard.publication/3mn26bjkkmh23",
"tags": [
"macOS Development",
"iOS Development",
"Xcode"
],
"textContent": "After a long while, I have finally adopted XcodeGen across my projects.\n\nXcodeGen lets me define an iOS or macOS project in project.yml, generate the .xcodeproj, and keep the generated Xcode project out of the parts I edit by hand. The main benefit: fewer Xcode project merge conflicts.\n\nI have been meaning to do this for a long time, having used RubyMotion and loved how it manages macOS/iOS projects with a Rakefile. For example:\n\nMotion::Project::App.setup do |app|\n app.name = 'My app name'\n app.identifier = 'my.bundle.id'\n app.short_version = '1.19.0'\n app.version = '130'\n app.deployment_target = '8.0'\n app.archs['iPhoneOS'] << 'arm64'\n app.archs['iPhoneSimulator'] << 'x86_64'\n app.interface_orientations = [:portrait]\n app.info_plist['UIRequiresPersistentWiFi'] = true\n app.info_plist['UILaunchStoryboardName'] = 'Launch Screen'\n app.info_plist['CFBundleIcons'] = { 'CFBundlePrimaryIcon' => { 'UIPrerenderedIcon' => true }}\n app.info_plist['CFBundleIcons'] = {\n 'CFBundlePrimaryIcon' => {\n 'CFBundleIconName' => 'AppIcon',\n 'CFBundleIconFiles' => ['AppIcon20x20', 'AppIcon29x29', 'AppIcon40x40', 'AppIcon60x60']\n }\n }\n\n…and to a certain extent, the usage of package.json in the JavaScript world.\n\nHOW I USE XCODEGEN\n\nXcodeGen is a tool that lets you define your project in a project.yml file and then generate the Xcode project for you. I check in project.yml, run xcodegen, and let it regenerate an up-to-date .xcodeproj.\n\nIf you use CocoaPods, run pod install again each time you run xcodegen.\n\nThe benefits of using XcodeGen's project.yml over manually editing Xcode project and workspace files are:\n\n * No more pesky merge conflicts in your project files\n * Much easier to copy and paste and edit an .yml file\n * Don't need to worry about moving and organising your source files within Xcode. Just create/move/rename files and re-run xcodegen\n\nCAN XCODEGEN RUN ON LINUX?\n\nXcodeGen is a Swift command-line tool, and the official README says it can generate projects on CI. In practice, I still treat it as part of my macOS/Xcode toolchain.\n\nThe generated output is an Xcode project. For my projects, I run xcodegen generate on macOS where Xcode is installed, then use CI to verify the generated project is not stale. I don't rely on Linux to generate or validate iOS/macOS Xcode projects.\n\nIf I wanted to experiment with Linux, I would keep the check narrow:\n\nxcodegen generate --spec project.yml\ngit diff --exit-code\n\nThat only answers one question: did project.yml produce the same .xcodeproj? It does not replace a real Xcode build.\n\n.GITIGNORE DANCE FOR PACKAGE.RESOLVED\n\nThe docs are pretty good. There's one thing to be careful of if you use SwiftPM because you'd want to check in Package.resolved, but it's in the project/workspace directories. So in git, you'd have to do this dance in .gitignore if you use a project:\n\n# xcodegen. Can't do only `*.xcodeproj` otherwise `Package.resolved` can't be made an exception as the directory isn't scanned\n*.xcodeproj\n*.xcworkspace/*\n## We want the SwiftPM lock file\n*.xcworkspace/xcshareddata/*\n!*.xcworkspace/xcshareddata/\n!*.xcworkspace/xcshareddata/swiftpm\n!*.xcworkspace/xcshareddata/swiftpm/Package.resolved\n\nand if you have a workspace (generally because you use CocoaPods; yes, you can mix SPM and CocoaPods):\n\n# xcodegen. Can't do only `*.xcworkspace` otherwise `Package.resolved` can't be made an exception as the directory isn't scanned\n*.xcodeproj\n*.xcworkspace/*\n## We want the SwiftPM lock file\n*.xcworkspace/xcshareddata/*\n!*.xcworkspace/xcshareddata/\n!*.xcworkspace/xcshareddata/swiftpm\n!*.xcworkspace/xcshareddata/swiftpm/Package.resolved",
"title": "I Finally Adopted XcodeGen Across my Projects",
"updatedAt": "2026-05-30T00:00:00.000Z"
}