Stack Tool · devtools
Tuist
Tuist is the tool I use to declaratively define and generate Xcode projects from Swift manifests, eliminating `project.pbxproj` merge conflicts for Inky iOS.
Visit tuist.io ↗Tuist makes `Project.swift` the source of truth for iOS projects, eliminating `project.pbxproj` merge conflicts and standardizing project structure across Total Ventures' mobile initiatives.
What it is
Tuist is a command-line tool that defines, maintains, and interacts with Xcode projects. Instead of directly editing the opaque `project.pbxproj` file, I define my project structure, targets, schemes, and dependencies in declarative Swift manifest files—primarily `Project.swift` and `Workspace.swift`. When I need an Xcode project, I run `tuist generate`, and it builds the `.xcodeproj` and `.xcworkspace` files based on those manifests. This approach means the generated project files are treated as disposable artifacts, not source code. It's an abstraction layer over Xcode's native project format, aimed at improving developer experience and consistency, especially in larger or modularized codebases.
How I use it
For Inky iOS, Tuist is central to the development workflow. Any time I add a new file to `Sources/`, modify build settings, or introduce a new target, I update the relevant `Project.swift` manifest. After changes, a quick `tuist generate` command rebuilds the Xcode project. This ensures the project always reflects the intended structure without manual Xcode GUI interaction, which often leads to errors or inconsistencies. Within my monorepo, where I manage multiple products like Inky and Total Formula 1, Tuist integrates well with pnpm Workspaces. It allows me to define shared modules and local Swift packages, which are then referenced across different iOS projects. This modularity is critical for agentic engineering; my AI agents can modify a `Project.swift` file for a new feature or module, then trigger `tuist generate` as part of their pipeline. This setup removes a significant point of friction that I learned the hard way with traditional Xcode project management. For build processes, Turbo orchestrates the `tuist generate` command and subsequent builds, ensuring efficient caching of generated outputs and faster iteration cycles.
Why this over alternatives
The primary driver for choosing Tuist was the `project.pbxproj` problem. I've spent too many hours resolving Xcode project merge conflicts, which are often non-obvious and prone to reintroduction. Tuist eliminates this by making `Project.swift` the source of truth, a human-readable and merge-friendly file. Alternatives like manual Xcode project setup are simply not scalable for a multi-product studio, nor do they enforce any consistency. While dependency managers like CocoaPods or Carthage handle external libraries, they don't address the core issue of project file generation and structure. Tuist provides a consistent, declarative way to define the entire project, which is invaluable for maintaining a clean architecture and onboarding new developers or, in my case, new AI agents. It forces a modular approach, encouraging the creation of smaller, well-defined targets and Swift packages, rather than a monolithic application target.
Where it falls short
Tuist introduces its own learning curve. Understanding the manifest syntax and the various configuration options in `Project.swift` takes time. Debugging issues within the manifest files can sometimes be opaque; error messages aren't always immediately clear, requiring a deeper dive into Tuist's documentation or source. The initial setup overhead is also higher than just opening Xcode and adding files. For very large projects with hundreds of targets, `tuist generate` can take a noticeable amount of time, though this hasn't been a significant bottleneck for my current scale with Inky iOS. It also requires discipline to ensure that any structural changes are reflected in the manifests, not just in the generated project. If a developer or agent accidentally edits the `.xcodeproj` directly, those changes will be overwritten on the next `tuist generate`. This is a feature, not a bug, but it requires a shift in workflow.
FAQs
- Does Tuist replace CocoaPods or SPM?
- No. Tuist manages your project structure and targets. It integrates with CocoaPods or Swift Package Manager (SPM) to handle external dependencies, but it doesn't replace their core function.
- How does this impact CI/CD?
- It simplifies CI/CD. The `tuist generate` command runs as an initial step, ensuring a clean, consistent project is built every time, reducing "works on my machine" issues.
- Is it only for Swift projects?
- Tuist is specifically designed for Xcode projects, which primarily means Swift and Objective-C codebases for iOS, macOS, tvOS, and watchOS.
See how I run a multi-brand studio with this stack.
See the full stack →