Monorepo with Swift: Code Organization for Beginners

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: Code Organization for Beginners



When you start developing applications in Swift for iOS or macOS, sooner or later you face the question: how to organize code so that it doesn't turn into chaos? Especially if you have several projects (for example, an iOS app, a watchOS extension, and a server-side part on Vapor). One modern approach is a monorepo. In this article, we will break down what a monorepo is, why it is needed in Swift development, and how to organize it in practice.



What is a monorepo and why is it needed?



A monorepo is an approach to code management where all projects, libraries, and modules are stored in a single repository (for example, in Git). Unlike multi-repositories, where each project lives in its own separate storage, a monorepo unifies everything in one place.



For Swift developers, this provides several advantages:



  • Single version of dependencies — you know exactly which version of a library is used across all projects.
  • Simplified refactoring — changing an API in one library is immediately visible in all dependent projects.
  • Shared settings — one SwiftLint, one CI/CD config, one set of formatting rules.
  • Easy search — everything is in one place, no need to switch between repositories.


However, there are nuances: a monorepo requires discipline and a proper structure, otherwise it turns into a "dump." But for beginners, this is an excellent way to learn how to organize code.



Monorepo structure for Swift projects



Suppose you are creating an iOS app with shared modules. A typical monorepo structure in Swift might look like this:



MyMonorepo/├── Apps/│   ├── iOSApp/          # Main iOS application│   │   ├── Sources/│   │   ├── Resources/│   │   └── Package.swift│   └── macOSApp/        # macOS version│       ├── Sources/│       └── Package.swift├── Packages/│   ├── Core/            # Common utilities (networking, logging)│   │   ├── Sources/│   │   └── Package.swift│   ├── UIComponents/    # Reusable UI components│   │   ├── Sources/│   │   └── Package.swift│   └── Analytics/       # Analytics module│       ├── Sources/│       └── Package.swift├── Scripts/             # Helper scripts├── .swiftlint.yml       # Unified linter config├── Package.swift        # Root manifest (optional)└── README.md


Note: here we use Swift Package Manager (SPM) — the standard tool for managing dependencies in Swift. Each module is a separate Swift Package that can be connected to applications.



How to create a monorepo in Swift: step-by-step guide



Let's create a simple monorepo with two modules and one application. Follow these steps in the terminal:



Step 1: Create the root directory and initialize Git



mkdir MyMonorepocd MyMonorepogit init


Step 2: Create the folder structure



mkdir -p Apps/iOSApp/Sourcesmkdir -p Packages/Core/Sourcesmkdir -p Packages/UIComponents/Sources


Step 3: Create Package.swift for the Core module



Create the file Packages/Core/Package.swift:



// swift-tools-version:5.9import PackageDescription

let package = Package( name: "Core", platforms: [ .iOS(.v16), .macOS(.v13) ], products: [ .library( name: "Core", targets: ["Core"]) ], targets: [ .target( name: "Core", path: "Sources") ])


Step 4: Write simple code in the Core module



Create Packages/Core/Source

Blogs

Book Recommendations