The basics of Swift Package Manager

Most of the code we write depends on external libraries. Libraries are pieces of code that can be used by many applications. The OS already comes with essential libraries we can use as building blocks, and all we have to do is import their modules. This is what we do when we need libraries like Foundation, SwiftUI, or UIKit. But what happens when we need to use a library that doesn’t come with the OS?

In this case, we can manually download the library and embed it in our project. This process gets complicated if we depend on multiple libraries, though. A library might also depend on other libraries, which means we would need to manually manage each sub dependency. Another problem we might face is dealing with versions. How do we know when to update a specific dependency?

Those problems are what make dependency managers exist. They automate those processes, making our lives simpler and allowing us to focus on writing code. SPM is Apple’s dependency manager and is part of the Swift project. It integrates with the Swift build system to provide us the full experience of downloading, compiling, linking, and updating dependencies. Xcode also integrates with it, exposing controls to use this tool.


SPM works by managing packages. A package is a flexible container of source code that can distribute libraries to clients. In this article, we’ll be using a simple open-source package called Time. More specifically, we’ll explore how we can use SPM to use this library in our code.

The examples in this article use Xcode 13.2.1. If you wish to follow along, create a new iOS project using Swift (the UI framework doesn’t matter).

Declaring Dependencies

To use a package in our iOS app, we first need to declare it as a dependency in the Package Dependencies screen:

  1. In the navigation area, select the project
  2. At the left bar, select the project again (not the target)
  3. At the top tab bar, select the Package Dependencies tab
The Package Dependencies screen on Xcode

Now we need to add the Time package:

  1. Copy the repository URL:
  2. Select the + button, under Packages
  3. Paste the copied URL in the search bar at the top
  4. In the dependency rule option, select “Up to Next Major Version”
Adding Time as a package

Xcode will then fetch this package and ask us which library we want to use (one package can distribute multiple libraries). This package is simple, it only distributes one:

Adding the Time product

Once we add this package to our project, Xcode will display it in the Package Dependencies list, in the navigation area:

The list of resolved packages in the navigation area

Package Resolution

After we declare the dependencies in our project, SPM will resolve them:

  1. Look at the URL and version of each package
  2. Fetch each dependency with the correct version
  3. Repeat this process for each sub dependency of a package if it has any
  4. Configure the packages with the project, allowing us to import their distributed libraries

After the package resolution phase, SPM generates a JSON file called Package.resolved. It contains which packages were resolved and what their versions are. SPM uses it to figure out whether a dependency needs to be updated or not. Here’s what this file looks like:

  "object": {
    "pins": [
        "package": "Time",
        "repositoryURL": "",
        "state": {
          "branch": null,
          "revision": "be6cbbbb97aa4570e3b51bd56f98ca3cf62aa3cb",
          "version": "0.9.2"
  "version": 1

Package.resolved is located in the swiftpm folder, inside your xcodeproj file:


It’s a good idea to put the swiftpm folder under version control. This way we can ensure every team member is using the right package versions.

Packages Location

The resolved packages are located in the derived data folder. A lot of times developers have problems with Xcode, and deleting this folder sometimes solves those issues. Just be aware that when you delete it, you’ll also delete the cached dependencies, forcing a new resolution of packages.

The Three SPM Actions

Once we have the packages in place, we can use three different actions for dealing with them:

Actions for dealing with SPM

Reset Package Caches

Use this action to erase the cached packages of our project from the derived data folder. SPM will automatically resolve the dependencies again.

Resolve Package Versions

Use this action to force a new resolution of dependencies. If your package.resolved file was updated by another team member, this action will ensure your local packages match the versions in that file.

Update to Latest Package Versions

The action name says it all. It will check if any dependency has available updates and will update them according to the dependency rule (e.g Up to next major). Semantic versioning is used to organize the package versions.

Be careful

Packages can come from third-party developers. Before using these packages, ensure the following:

  1. You understand what the package does and what sub dependencies it uses
  2. It comes from a trusted source
  3. If it’s an open-source package, ensure it’s maintained by the community (check the latest changes, number of stars, and so on)
  4. The package license allows your application to use it


In this article, we’ve explored how SPM works. Here’s what we learned:

  • What SPM and packages are
  • How to add packages to an Xcode project
  • What package resolution is
  • Where Xcode stores the resolved packages
  • How to manage the packages in Xcode
  • What to take into account when adding a package

In the upcoming article, we’ll explore how we can create a Swift package and what it looks like in terms of structure.

2 thoughts on “The basics of Swift Package Manager

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s