Monorepository with Swift: Code Organization for iOS and macOS Projects

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Monorepo with Swift: organizing code for iOS and macOS projects



In modern iOS and macOS development, the choice of code management strategy directly affects development speed, refactoring quality, and team collaboration convenience. The traditional approach with many separate repositories (polyrepo) often leads to dependency duplication, version synchronization difficulties, and codebase fragmentation. An alternative is a monorepo — a single storage for all modules, libraries, and project applications. In this article, using Swift and the Apple ecosystem as an example, we will analyze how to organize a monorepo, which tools to use, and what pitfalls to consider.



What is a monorepo and why is it needed in Swift projects



A monorepo is a version control strategy where all project code (multiple applications, libraries, configurations) is stored in a single Git repository. In the context of Swift, this means you can have in one repository:



  • iOS application (e.g., MyApp)
  • macOS application (MyMacApp)
  • shared model library (CoreModels)
  • networking layer (Networking)
  • UI components (UIComponents)
  • tests and CI scripts


Advantages of a monorepo for Swift projects:

  • Single version of dependencies — all modules use the same version of a library (e.g., Alamofire or SwiftUI), which eliminates conflicts.
  • Atomic commits — changes to a library's API and its usage in the application are committed in a single commit, simplifying code review and rollback.
  • Simplified refactoring — you can rename a public method in a module and immediately fix all call sites in the same repository.
  • Shared CI/CD — one pipeline for building and testing all components.


Tools for working with a monorepo in Swift



In the Apple ecosystem, there are two main tools for organizing a monorepo: Swift Package Manager (SPM) and Tuist. Let's look at their features.



Swift Package Manager (SPM)

SPM is a built-in package manager that is well-suited for monorepos. You define modules via Package.swift, and Xcode automatically resolves dependencies. Example structure:



MyMonorepo/├── Package.swift├── Sources/│   ├── CoreModels/│   │   └── Models.swift│   ├── Networking/│   │   └── APIClient.swift│   └── UIComponents/│       └── ButtonView.swift├── Apps/│   ├── MyApp/│   │   └── (iOS project)│   └── MyMacApp/│       └── (macOS project)└── Tests/    ├── CoreModelsTests/    └── NetworkingTests/


Example Package.swift for such a monorepo:



// swift-tools-version:5.9import PackageDescription

let package = Package( name: "MyMonorepo", platforms: [ .iOS(.v16), .macOS(.v13) ], products: [ .library(name: "CoreModels", targets: ["CoreModels"]), .library(name: "Networking", targets: ["Networking"]), .library(name: "UIComponents", targets: ["UIComponents"]), ], dependencies: [ .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.8.0") ], targets: [ .target(name: "CoreModels"), .target( name: "Networking", dependencies: ["CoreModels", "Alamofire"] ), .target( name: "UIComponents", dependencies: ["CoreModels"] ), .testTarget(name: "CoreModelsTests", dependencies: ["CoreModels"]), .testTarget(name: "NetworkingTests", dependencies: ["Networking"]), ])

Blogs

Book Recommendations