Swift Package Manager

Swift Package Manager, often shortened to SwiftPM, organizes code into reusable packages and downloads packages that other developers share. A package bundles source files, tests, and a description file. Xcode and the command line both understand packages.

Imagine a library where each shelf holds ready-made parts for your project. You list the parts you need, and the library delivers the correct versions. SwiftPM acts as that librarian for your code.

Diagram: Package Layout

 Greeter/
 +-- Package.swift              (the recipe)
 +-- Sources/
 |    +-- GreeterKit/
 |         +-- Greeter.swift    (your code)
 +-- Tests/
      +-- GreeterKitTests/
           +-- GreeterTests.swift

Key Terms

  • A package is a folder of code with a Package.swift file.
  • A target is one buildable unit inside the package, such as a library or a test group.
  • A product is what the package offers to others, such as a library or an executable.
  • A dependency is another package that your package needs.

Creating a Package

Run these commands in a terminal to start a command-line program.

mkdir Greeter
cd Greeter
swift package init --type executable
swift build
swift run

The init command creates the folder layout. The build command compiles the code, and run starts the program. Use --type library to create a reusable library.

Reading Package.swift

The manifest file is itself Swift code. It describes the package in a clear, structured way.

// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "Greeter",
    platforms: [.macOS(.v13)],
    products: [
        .library(name: "GreeterKit", targets: ["GreeterKit"])
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-algorithms",
                 from: "1.2.0")
    ],
    targets: [
        .target(
            name: "GreeterKit",
            dependencies: [
                .product(name: "Algorithms", package: "swift-algorithms")
            ]
        ),
        .testTarget(
            name: "GreeterKitTests",
            dependencies: ["GreeterKit"]
        )
    ]
)

The opening comment line states the lowest SwiftPM version the file needs. The dependencies list names outside packages, and each target lists the products it uses.

Version Rules

Packages use semantic versioning with three numbers: major, minor, and patch, as in 1.2.0. A major change may break old code. A minor change adds features safely. A patch change fixes bugs.

.package(url: "...", from: "1.2.0")            // 1.2.0 up to below 2.0.0
.package(url: "...", exact: "1.2.0")           // only 1.2.0
.package(url: "...", "1.2.0"..<"1.5.0")        // inside a range

The from rule fits most projects. SwiftPM picks the newest compatible version and records the exact choice in a file named Package.resolved. Teammates build with identical versions.

Adding a Package in Xcode

  • Open the project and choose File and Add Package Dependencies.
  • Paste the package address into the search field.
  • Pick a version rule and press Add Package.
  • Choose the target that will use the package.

Use the package in code with an import line.

import Algorithms

let letters = ["a", "b", "c"]
for pair in letters.uniquePermutations(ofCount: 2) {
    print(pair)
}

Everyday Commands

swift build            compile the package
swift run              build and run an executable
swift test             run every test
swift package update   fetch newer allowed versions
swift package resolve  download the recorded versions

Choosing Packages Wisely

Every dependency adds code you do not control. Check the package license, the date of the latest update, and the number of open issues. Prefer small packages with a clear purpose and active maintenance.

Common Mistakes

Choosing a version rule that is too loose lets a surprise update change behavior. Commit the Package.resolved file to version control to guarantee that every teammate builds with the same versions.

Mixing up targets and products causes confusion for newcomers. A target is a unit of code inside your package. A product is the item that other projects can import.

Real-World Use

Teams split large apps into local packages such as networking, design components, and data models. Each package builds and tests on its own, and builds finish faster. Open-source libraries for images, charts, and networking arrive through the same mechanism.

Key Takeaways

  • SwiftPM organizes code into packages with targets and products.
  • Package.swift describes the package in Swift code.
  • Semantic versions control which updates your project accepts.
  • Xcode and the terminal both add, build, and test packages.