Migrating Your Application to Swift Package Modules


Applications will grow over time and without a good architecture, become unmanageable and difficult to maintain. Here at OkCupid, we decided that the best way to ensure clean code and good organization is to break the code base into easily manageable pieces. Luckily, Apple has created a great tool to make this task easier.


Another big benefit of Swift Packages is the ability to run them alone to reduce compile time during development and make testing easier. We have now come to the point where our test application can compile over 20 modules and 10 dependencies from a clean build in less than a minute, and incremental changes to individual modules can take as little as 10 seconds to compile and run.

In this tutorial, we’ll show you how you can get started adding Swift packages to your own project to keep your code clean and usable.

You can find a sample project for this tutorial here.


Since we are doing this for organizational reasons, and not to share code between applications, it will be easiest to use the monorepo concept. This means that we are going to add a new Swift package as part of our current application’s Git repository.

For demonstration purposes, we will use a new project called Sample and embed it in the workspace of the same name.

First, let’s create a folder called Modules in the git root directory where we can store all our Swift packages.

Note: Make sure your project is inside the workspace first.

Now click on the plus symbol in the lower left corner and then select “New Swift Package”. Make sure the new Swift package is placed in the Modules folder.

After that, everything should look like this:


Now let’s fix and clean up the Package.swift file and look at the different parts.

let package = Package(
    name: "NewModule", // This is the name of the package
    defaultLocalization: "en", // This allows for localization
    platforms: [.iOS(.v12)], // Our minimum deployment target is 12
    products: [
            name: "NewModule",
            type: .static, // This is a static library
            targets: ["NewModule"]
    dependencies: [
    targets: [
            name: "NewModule",
            dependencies: [
            path: "Sources", // This allows us to have a better folder structure
            resources: [
                .process("Media.xcassets") // We will store out assets here
            name: "NewModuleTests", // Unit tests
            dependencies: ["NewModule"]

Package.swift is a file that tells the compiler how to build your Swift package. The file declares what to include and what not to include, and how packages should be built.

As you can see, we need a static library, and we also want to be able to localize the module and include resources.


The Swift package comes by default with everything you need to compile a Swift package on all platforms. This is great, but we don’t need everything it provides for our particular use case as an iOS app.

This is how it should look before the changes:

Let’s delete the files LinuxMain.swift and XCTestManifests.swiftsince we won’t be running them on Linux. Then rename the folder NewModule in Public and create a folder Internal for better organization of access control. Now let’s rename NewModule.swift in NewModuleViewController.swiftso that we can check if it works.

In the end, everything should look like this.


The code above should give us UIViewController with an orange background to confirm that it is working correctly.

With the project selected and our target highlighted, click the plus sign under “Frameworks, Libraries, and Embedded Content.”

Now select our new library and click “Add”.

Now let’s go back to the application and use our new module by editing Main.storyboard and changing the class to NewModuleViewController.swift, and “Module” – on NewModule


Now, when we launch the application, it becomes clear that it is using ViewController from our new module! ?


Now you can see how easy it is to split your code into Swift packages. This process can then be used to move your loosely coupled code directly into modules that can be compiled and run independently of the main application. In the next tutorial, I will discuss how to best interact between multiple modules and the main purpose of an application when scaling up mastering the Swift package.

The translation of the article was prepared as part of the start of recruiting students for the course “iOS Developer. Basic” prepared a traditional translation of the article.

We also invite everyone to a two-day intensive “Creating the simplest application without a single line of code.” On the first day, we will discuss and do:
– What is Xcode?
– How the screens are drawn
– Let’s add buttons and input fields to the screens. Let’s create an authorization screen.
– Let’s create a second screen of our application and add a transition to it from the authorization window.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *