Back to all blogposts

Swift Package Manager Guide – the time to shine is now! (1/2)

Anna Widera

Anna Widera

iOS developer

The Swift Package Manager has been around for some time, but it is with the release of Xcode 11 that it finally gets its true chance to shine. Now you can use it across the entire Apple ecosystem. Which makes for a great opportunity to delve a bit deeper into the subject. Learn more about Swift Package Manager and its new features from our 2-part guide.

Regardless of whether you use 3rd party dependencies, develop your own internal frameworks, or just want to extract part of your app’s code to make it more modular and orderly (or everything at once), Swift Package Manager advantages can go a long way to help you out. It’s one of the most flexible Swift tools. With the release of Xcode 11, it’s going to become a very important part of Apple’s IDE. Now, SPM Apple packages work with all Apple platforms, including the iOS system (so far, it supported command line tools and server-side Swift apps only). If you haven’t used Xcode Swift Package Manager yet, now is the best time to give it a try! Time for a quick Swift Package Manager tutorial!

Swift Package Manager features for iOS and more

What exactly can Swift Package Manager do for you?

  • It automatically adds dependencies to Frameworks, Libraries and Embedded Content in a target (unlike Carthage).
  • It automatically adds embedded dependencies (packages used by libraries you added) to your Swift project (another missing feature in Carthage).
  • It allows you to delete unneeded libraries at a click of a button (missing in CocoaPods).
  • It makes it easy to edit packages by overwriting references to dependencies with a local version.

In my 2-part Swift Package Manager guide, I’ll show you how to take advantage of SPM’s potential. Today, I’ll focus on using SPM to consume both private and public libraries. The soon-to-be published 2nd part will tackle the issue of using SPM to help create your own modules and edit the source code of your dependencies. I hope that by the end of the guide, you’ll love the idea of working with Swift and SPM as much as I do!

Xcode -> File -> New 😍

Let’s say you’re working on a project of an iOS app for a client from the insurance industry. A desktop app for agents already exists. Now, the task is to create a simplified version for potential clients. Its main purposes include gathering data (basic personal data, risk factors and declarations) and calculating premiums.

Create a new Workspace (File -> New… -> Workspace) and a new app project (File -> New… -> Project). Also, make sure:

  • to add the project to the Workspace and to its group.
  • not to tick the ‘Create Git repository on my Mac‘ box. We will later create a high-level repository that will include the whole Workspace.

A screenshot shows how to create git repository on Mac.Now, create a repository at the same level as the catalog that contains the *.workspace file and the project directory. I wasn’t able to force Xcode’s version control (In the Source control menu) to let me create a repository where I wanted to, so I did it via the terminal (see the screen below). I also added a .gitignore file.

A screenshot shows how to create a terminal repository.

📦 Internally developed library

Let’s assume that the team responsible for the macOS app created a library called InsuranceCulculator, which includes all the logic that calculates premiums. Using the same library across both apps will not only speed things up, but also ensure that agents and clients will see the same results.

* By the way, if you are wondering how to share your code to your internal team or even the entire public, so that it can be added with Swift Package Manager, make sure to read the upcoming second part of the guide. In doing so, our SPM story will come a full circle. ♾️⚠️

In order to access packages in your company’s repository, make sure to properly configure your Github/Bitbucket/GitLab account in Xcode (Xcode -> Preferences -> Accounts).

A screenshot showing repository configuration in xCode.

Now, that we took care of all that, we can add our first Swift package! 🎉

Adding dependencies to a project

Go to File -> Swift Packages -> Add Package Dependency – a new window will open. By default, it shows all of the repositories you own. A search can be used to find a specific repository out of those you have access to. Choose insurancecalculator and click Next. Now, choose which version you want to use (more about available options in a moment) and specify a target for this new dependency. It’s done!

An example of how to add packaging insurance calculator.

Swift Package Manager can now download a repository that contains the library, checkout the proper version, add the library to Frameworks, Libraries, and Embedded Content in the specified target and add a reference to the dependency in the project. All of that happens automatically (or magically, if you’d rather 🔮).

🥳 Voilà! Now you can import InsuranceCalculator to the InsuranceApp and get to calculating those premiums!

import UIKit
import InsuranceCalculator

class ViewController: UIViewController {

override func viewDidLoad() {

let customer = Person(age: 33)
let interval = DateInterval(start: Date(), duration: 60*60*24*365)
let premiums = InsuranceCalculator.calculatePremiums(for: [.car, .flat], insuredBy: customer, in: interval)
print("calculated premiums: \(premiums)")

The console now shows the value of calculated premiums to be 20813760.0

Versions, versions, versions…

Now is a good moment to learn how you can specify the version of a dependency you add to a project.

The version management process is quite similar to what you might know from Carthage or Cocoapods. There are three groups of rules at our disposal:

  • version-based: prioritizes the version of a given library (according to the Semantic Versioning 2.0.0 standard),
  • branch-based: references a branch in the package’s repository,
  • Commit-based: references a specific commit (using its SHA-1 hash).

The version-based strategy is the most popular one and is usually recommended. It allows you to easily specify how important updates (referred to in this context as significant changes) should be accepted. The choices include:

.upToNextMinor(from: "5.0.1")

.upToNextMajor(from: "5.0.1")

A more restrictive approach which specifies a range (e.g. 3.1.0” … “3.1.2”) can also be used. Another, most restrictive option is to simply specify a single compatible version (.exact (“5.0.1”)). This approach is usually not recommended, since it can cause conflicts in the dependency graph if more libraries use the same dependencies in different versions. You will also lose access to bug fixes.

You also should keep in mind that before you publish your package’s version, you are required to remove all dependencies based on branches and commits.

It works for me…

Let’s say that your friend is cloning the repository and for some reason can’t build the Swift project. If you come across such problems, check if your friend properly connected their account to the company repository in Xcode. You should also check if they use SSH.

An image with building project errors.

📦 3rd party library

So far so good! Still, I doubt you have missed this awful line 😉

let interval = DateInterval(start: Date(), duration: 60*60*24*365)

We can definitely do better. Start by adding the SwiftDate library. It will help us to express the duration time in a more concise manner.

Use the File -> Swift Packages -> Add Package Dependency… menu to add a link to the SwiftDate GitHub repository. The remaining steps are the same as before.

An example of how to add Swift date.

🥳 Voilà! SwiftDate is ready to be imported and used! 🎉

import UIKit
import InsuranceCalculator
import SwiftDate

class ViewController: UIViewController {
override func viewDidLoad() {

let customer = Person(age: 33)
let interval = DateInterval(start: Date(), duration: 365.days.timeInterval)
let premiums = InsuranceCalculator.calculatePremiums(for: [.car, .flat], insuredBy: customer, in: interval)
print("calculated premiums: \(premiums)")

The value of calculated premiums remains the same: 20813760

A screenshot showing value of calculated premiums.

It was easy, wasn’t it? Thank you, Swift Package Manager!

Removing dependencies

Want to remove some dependencies? It only takes a moment! Select a project in the Projects and targets list in Xcode, go to the Swift Packages tab (next to Info and Build settings), mark packages to be removed and click the “-” sign. Done.


In the first part of my Swift Package Manager guide, I focused on working with existing public and private packages. Package management with SPM is really fun. It only takes a couple clicks to add a new library in a specific version. All packages are updated according to the rules you choose. In addition to that, a new Project Navigator section Swift Package Dependencies makes it easy to view all the dependencies we have added to a project. With that, finding unneeded dependencies and keeping things clean is a walk in the park.

Do you now feel like trying and using Swift Package Manager in your everyday work? You don’t necessarily need a new Swift project to do that. There are plenty of articles available online that will guide you through the process of migrating from CocoaPods or Carthage to SPM. It will also serve as a great opportunity to review the libraries in your projects and check if there is something that should be removed. Also, if you want even more Swift related content, check out my introduction to protocol-oriented programming with Swift. Take your time learning even more Swift tools than can immensely improve your workflow!

You may also like

State of Frontend 2022 - Global report

With 3700 devs, 19 experts, 13 topics. This report will rock your front!

Claim free copy

What would you like to do?

    This site is protected by reCAPTCHA and the Google
    Privacy Policy and Terms of Service apply.

    They are more than just a software company. They are the partner who will help you achieve what you want to achieve.

    Nick Gold

    Managing Director at Speakers Corner


    Thank you for your inquiry!

    We'll be back to you shortly to discuss your needs in more detail.