Overview
Migrating an existing Xcode project to Tuist allows you to gain better control over your project structure, enable powerful features like binary caching, and simplify dependency management. This guide walks you through the migration process step by step.Before You Begin
Prerequisites
- Xcode installed on your Mac
- Tuist CLI installed (
curl -Ls https://install.tuist.io | bash) - Basic familiarity with your current project structure
- Backup of your existing project (commit all changes to git)
Understanding the Benefits
Migrating to Tuist provides:- Consistency: Projects are defined declaratively and remain simple over time
- Faster builds: Enable binary caching and selective testing
- Better collaboration: Fewer merge conflicts in project files
- Dependency management: Unified approach to external dependencies
- Graph validation: Automatic detection of dependency cycles and issues
Migration Process
Add the
-Tuist suffix to your project name to prevent conflicts with the existing Xcode project. You can remove it after completing the migration.Extend your continuous integration pipeline to build and test the Tuist-generated project. This ensures each migration step is valid:
name: Tuist Validation
on: [pull_request]
jobs:
validate:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install Tuist
run: curl -Ls https://install.tuist.io | bash
- name: Install dependencies
run: tuist install
- name: Generate project
run: tuist generate
- name: Build project
run: xcodebuild build -workspace MyApp-Tuist.xcworkspace -scheme MyApp-Tuist
mkdir -p xcconfigs/
tuist migration settings-to-xcconfig -p MyApp.xcodeproj -x xcconfigs/MyApp-Project.xcconfig
import ProjectDescription
let project = Project(
name: "MyApp-Tuist",
settings: .settings(configurations: [
.debug(name: "Debug", xcconfig: "./xcconfigs/MyApp-Project.xcconfig"),
.release(name: "Release", xcconfig: "./xcconfigs/MyApp-Project.xcconfig"),
]),
targets: [
// Targets will go here
]
)
let package = Package(
name: "MyApp",
dependencies: [
.package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0"),
.package(url: "https://github.com/onevcat/Kingfisher", .upToNextMajor(from: "7.12.0")),
]
)
Override the product type for specific packages using
productTypes in PackageSettings. By default, Tuist treats all packages as static frameworks.Migrate from the top of the list (most depended upon) to the bottom. This ensures dependencies are available as you migrate dependent targets.
tuist migration settings-to-xcconfig -p MyApp.xcodeproj -t TargetName -x xcconfigs/TargetName.xcconfig
.target(
name: "TargetName",
destinations: .iOS,
product: .framework,
bundleId: "com.example.targetname",
sources: ["Sources/TargetName/**"],
resources: ["Resources/TargetName/**"],
dependencies: [
.external(name: "Alamofire"),
.target(name: "OtherTarget")
],
settings: .settings(configurations: [
.debug(name: "Debug", xcconfig: "./xcconfigs/TargetName.xcconfig"),
.release(name: "Release", xcconfig: "./xcconfigs/TargetName.xcconfig"),
])
)
Use xcdiff to compare the generated project with the original to verify correctness.
.target(
name: "TargetNameTests",
destinations: .iOS,
product: .unitTests,
bundleId: "com.example.targetname.tests",
sources: ["Tests/TargetNameTests/**"],
dependencies: [
.target(name: "TargetName"),
.xctest
],
settings: .settings(configurations: [
.debug(name: "Debug", xcconfig: "./xcconfigs/TargetNameTests.xcconfig"),
.release(name: "Release", xcconfig: "./xcconfigs/TargetNameTests.xcconfig"),
])
)
Troubleshooting
Compilation Errors Due to Missing Files
If files aren’t contained in directories matching the target structure: Compare source lists:Build Settings Conflicts
If you encounter conflicts between project and target settings:- Review the extracted
.xcconfigfiles - Ensure inheritance is correct using
$(inherited) - Remove duplicate settings between project and target levels
Dependency Graph Cycles
Tuist validates the dependency graph and will error on cycles:External Dependencies Not Found
If external dependencies aren’t resolving:Test Target Configuration
If tests fail after migration:- Verify the test target has
.xctestdependency - Check that test host configuration matches the original
- Ensure test resources are properly included
Migration Checklist
Use this checklist to track your migration progress:- Create Tuist scaffold files
- Set up CI validation pipeline
- Extract project build settings to xcconfig
- Extract package dependencies
- Determine target migration order
- Migrate each target (create separate PRs)
- Extract target build settings
- Define target in Project.swift
- Validate builds successfully
- Migrate associated test target
- Validate tests pass
- Update CI/CD pipelines
- Remove old .xcodeproj file
- Update team documentation
Next Steps
After completing the migration:Enable Binary Caching
Speed up builds with Tuist’s binary caching feature
Optimize Project Structure
Learn best practices for organizing your Tuist projects
Manage Dependencies
Master dependency management with Tuist
Set Up CI/CD
Configure continuous integration for your Tuist project