What is Tuist?
Tuist is a command-line tool that helps you generate, maintain, and interact with Xcode projects at scale. Unlike package managers like CocoaPods or Swift Package Manager that manage dependencies, Tuist manages your Xcode project configuration itself.
Instead of dealing with complex .xcodeproj
files that are prone to merge conflicts and hard to maintain, Tuist lets you define your entire project structure in simple Swift files. Think of it as "Infrastructure as Code" but for iOS projects.
Why Use Tuist?
1. No More Merge Conflicts
.xcodeproj
files are XML-based and notoriously difficult to merge. With Tuist, you define your project in Project.swift
using Swift code, which is much easier to review and merge.
2. Consistency Across Teams
Everyone on your team generates the same project configuration from the same manifest files.
3. Easier Modularization
Tuist makes it simple to break your app into multiple modules and frameworks, improving build times and code organization.
4. Build Time Optimization
Tuist can cache compiled frameworks and share them across team members, dramatically reducing build times.
5. Cleaner Git History
You can .gitignore
the generated .xcodeproj
and .xcworkspace
files, keeping only the manifest files in version control.
When Should You Use Tuist?
Use Tuist if:
- You work on medium to large projects
- You have a team where merge conflicts are common
- You want to modularize your app
- You're starting a new project and want to set it up right
Installation
Install Tuist using Homebrew:
brew install tuist
Or using the official installer:
curl -Ls https://install.tuist.io | bash
Verify the installation:
tuist --version
Creating Your First Tuist Project
Let's build a simple iOS app with MVVM architecture using Tuist.
Step 1: Initialize a New Project
# Create a directory for your project
mkdir MyTuistApp
cd MyTuistApp
# Initialize Tuist
tuist init
Tuist will ask you a few questions:
- Name: Enter your app name (e.g., "MyApp")
- Platform: Select iOS
- Server: Choose No for now
This creates:
-
Project.swift
- Your project configuration -
Tuist/
- Tuist configuration folder - A basic folder structure
Step 2: Navigate to Your Project
cd MyApp # Navigate into the generated folder
Step 3: Create Your Folder Structure
# Create organized directories for MVVM
mkdir -p Sources/App
mkdir -p Sources/Models
mkdir -p Sources/ViewModels
mkdir -p Sources/Views
mkdir -p Resources/Assets.xcassets
mkdir -p Tests
Step 4: Update Project.swift
Replace the contents of Project.swift
with:
import ProjectDescription
let project = Project(
name: "MyApp",
targets: [
.target(
name: "MyApp",
destinations: .iOS,
product: .app,
bundleId: "com.example.myapp",
infoPlist: .extendingDefault(
with: [
"UILaunchScreen": [:],
]
),
sources: ["Sources/**"],
resources: ["Resources/**"],
dependencies: []
),
.target(
name: "MyAppTests",
destinations: .iOS,
product: .unitTests,
bundleId: "com.example.myapp.tests",
infoPlist: .default,
sources: ["Tests/**"],
dependencies: [
.target(name: "MyApp")
]
)
]
)
Step 5: Create the App Entry Point
Create Sources/App/MyAppApp.swift
:
import SwiftUI
@main
struct MyAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Step 6: Create Your Source Files
Create Sources/Models/User.swift
:
import Foundation
struct User: Identifiable {
let id = UUID()
let name: String
}
Create Sources/ViewModels/ContentViewModel.swift
:
import Foundation
class ContentViewModel: ObservableObject {
@Published var greeting = "Hello from Tuist!"
}
Create Sources/Views/ContentView.swift
:
import SwiftUI
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
var body: some View {
VStack {
Text(viewModel.greeting)
.font(.largeTitle)
.padding()
}
}
}
Step 7: Generate and Run
Now generate your Xcode project:
tuist generate
This will:
- Read your
Project.swift
configuration - Generate the
.xcodeproj
file - Automatically open it in Xcode
Press ⌘ + R to build and run your app!
Project Structure
Your final structure should look like this:
MyApp/
├── Project.swift # Project configuration
├── Tuist/ # Tuist settings
│ └── Config.swift
├── Sources/
│ ├── App/
│ │ └── MyAppApp.swift
│ ├── Models/
│ │ └── User.swift
│ ├── ViewModels/
│ │ └── ContentViewModel.swift
│ └── Views/
│ └── ContentView.swift
├── Resources/
│ └── Assets.xcassets/
└── Tests/
└── MyAppTests.swift
Common Tuist Commands
# Initialize a new project
tuist init
# Generate Xcode project
tuist generate
# Clean generated files
tuist clean
# Edit project manifests in Xcode
tuist edit
# Visualize project dependencies
tuist graph
# Get help
tuist --help
Key Benefits in Practice
Before Tuist:
- Manual Xcode project configuration
- Frequent merge conflicts in
.xcodeproj
- Inconsistent project setup across team
- Hard to refactor or modularize
After Tuist:
- Project defined in Swift code
- Easy code reviews for project changes
- Consistent project generation
- Simple modularization and scaling
gitignore Configuration
Add these to your .gitignore
:
# Tuist generated files
*.xcodeproj
*.xcworkspace
Derived/
# Keep Tuist manifests
!Tuist/
Conclusion
By defining your project as code, you gain consistency, reduce conflicts, and make scaling easier.
Whether you're starting a new project or looking to improve an existing one, Tuist provides the tools to manage complexity as your app grows.
Top comments (1)
.xcodeproj files are XML-based and notoriously difficult to merge. With Tuist, you define your project in Project.swift using Swift code, which is much easier to review and merge.