Swift Package Manager

Reviewed & published by Brayan K

SwiftPM is the official way to organise code and pull in libraries. You'll read a Package.swift manifest, understand targets and products, declare dependencies, and add packages in Xcode and from the terminal.

Part of the free Swift course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

📊 Manifest Vocabulary

TermMeaning
Package.swiftThe manifest (Swift code)
targetA module that gets built
productA library/executable to share
dependenciesExternal packages you rely on
.testTargetA target holding tests

1️⃣ The Package.swift Manifest

The manifest is real Swift. It names the package, lists products (what consumers use) and targets (modules of code that build them).

// swift-tools-version:5.9
import PackageDescription

// Package.swift is the manifest — it's REAL Swift code, not a config file.
let package = Package(
    name: "Utilities",
    products: [
        // A product is what others can use: a library or an executable.
        .library(name: "Utilities", targets: ["Utilities"]),
    ],
    targets: [
        // A target is a module of code that gets built.
        .target(name: "Utilities"),
        .testTarget(name: "UtilitiesTests", dependencies: ["Utilities"]),
    ]
)

Your turn. Fill in the product and target factory methods.

// 🎯 YOUR TURN — replace each ___ then build with 'swift build'.
// swift-tools-version:5.9
import PackageDescription

let package = Package(
    name: "Greeter",
    products: [
        .___(name: "Greeter", targets: ["Greeter"]),   // 👉 a reusable library
    ],
    targets: [
        .___(name: "Greeter"),                          // 👉 a code module
    ]
)

// ✅ Once filled in, 'swift build' compiles a Greeter library.

2️⃣ Dependencies

List external packages in the dependencies array with a version rule, then give a target access by naming the dependency's product.

// swift-tools-version:5.9
import PackageDescription

let package = Package(
    name: "MyApp",
    dependencies: [
        // List external packages here, pinned to a version rule.
        .package(url: "https://github.com/example/Networking.git",
                 from: "1.2.0"),
    ],
    targets: [
        .target(
            name: "MyApp",
            // A target gains access by naming the dependency's product.
            dependencies: [
                .product(name: "Networking", package: "Networking")
            ]
        ),
    ]
)

Now you try. Fill in the array that lists external packages.

// 🎯 YOUR TURN — add a dependency.
// swift-tools-version:5.9
import PackageDescription

let package = Package(
    name: "App",
    ___: [                                              // 👉 array that lists external packages
        .package(url: "https://github.com/x/Logger.git", from: "2.0.0"),
    ],
    targets: [
        .target(name: "App", dependencies: [
            .product(name: "Logger", package: "Logger")
        ]),
    ]
)

// ✅ Once filled in, App can 'import Logger'.

3️⃣ Building from the Terminal

SwiftPM ships with the toolchain. Build, test, and run a package with a few commands — no Xcode required.

# From the package's root folder, in your terminal:

swift build      # compile the package
swift test       # run the test targets
swift run        # build and run an executable product

# Create a brand-new package skeleton:
swift package init --type library

Pro Tips

Common Errors (and the fix)

📋 Quick Reference

TaskCodeNotes
Library product.library(name:targets:)to share
Code module.target(name:)builds source
Tests.testTarget(name:dependencies:)unit tests
Dependency.package(url:from:)external pkg
Use it.product(name:package:)per target
Buildswift buildcompile

Mini-Challenge: Write a Manifest

Author a Package.swift for a MathKit library with a test target, then build it.

// 🎯 MINI-CHALLENGE: Write a package manifest
// Create a Package.swift for a package named "MathKit" that:
//   1. Declares swift-tools-version:5.9 and imports PackageDescription.
//   2. Exposes a .library product "MathKit" built from a "MathKit" target.
//   3. Has a .testTarget "MathKitTests" depending on "MathKit".
//   4. Bonus: add a dependency on a fictional package and wire it into MathKit.
//
// Then run 'swift build' to confirm it compiles.

// your manifest here

🎉 Lesson Complete!

Practice quiz

Which file defines a Swift package?

  • Info.plist
  • Package.swift
  • project.pbxproj
  • package.json

Answer: Package.swift. Package.swift is the manifest that describes a Swift package.

The Package.swift manifest is written in...

  • JSON
  • YAML
  • Swift
  • XML

Answer: Swift. The manifest is real Swift code using the PackageDescription API.

What does a 'target' represent in a package?

  • A build setting
  • A module of source code (or tests) that is built
  • A remote server
  • A device

Answer: A module of source code (or tests) that is built. A target is a basic building block: a module of code that gets compiled.

What does a 'product' expose?

  • A library or executable made from targets, usable by others
  • A test result
  • A storyboard
  • A provisioning profile

Answer: A library or executable made from targets, usable by others. Products are libraries or executables that targets build into for consumers.

Where do you list external packages your package relies on?

  • In targets only
  • In Info.plist
  • In a .gitignore
  • In the dependencies array

Answer: In the dependencies array. The dependencies array of the manifest lists external packages.

How does a target gain access to a dependency?

  • Automatically
  • By naming it in that target's dependencies
  • Via Info.plist
  • It cannot

Answer: By naming it in that target's dependencies. A target must list the dependency in its own dependencies to import it.

Which command builds a package from the terminal?

  • swift compile
  • swift make
  • swift build
  • spm build

Answer: swift build. swift build compiles the package using SwiftPM.

How do you usually add a package to an app in Xcode?

  • File > Add Package Dependencies and paste the repo URL
  • Drag a .zip in
  • Edit Info.plist
  • Copy source files manually

Answer: File > Add Package Dependencies and paste the repo URL. Xcode adds packages via File > Add Package Dependencies using the repo URL.

Specifying .upToNextMajor(from: "1.2.0") controls...

  • The Swift version
  • The deployment target
  • The product name
  • The allowed dependency version range

Answer: The allowed dependency version range. Version rules like upToNextMajor pin which dependency versions are allowed.

Test targets are typically declared with...

  • .executableTarget
  • .testTarget
  • .binaryTarget
  • .systemLibrary

Answer: .testTarget. .testTarget declares a target containing unit tests.

Continue this course

Frequently asked questions

What is Package.swift?

Package.swift is a package's manifest: the single file that describes its name, products, targets, and dependencies. It is not a static config file but real Swift code that uses the PackageDescription API, so you build up a Package value programmatically. The first line declares the Swift tools version, which tells SwiftPM which manifest features are available.

What is the difference between a target and a product?

A target is the basic unit of code SwiftPM compiles: a module of source files, or a test target. A product is what the package exposes to consumers, built from one or more targets, and is either a library you import or an executable you run. In short, targets build the code internally, and products publish it for others to use.

How do I add a dependency on another package?

Add an entry to the manifest's dependencies array with .package(url:from:) (or another version rule), pointing at the other package's Git URL. Then, in each target that needs it, list the dependency under that target's dependencies using .product(name:package:). Only after both steps can your code import the dependency's module.

How do version rules like from work?

Version rules pin which versions of a dependency are acceptable, following semantic versioning. from: "1.2.0" is shorthand for up to the next major version, allowing 1.2.0 and later 1.x updates but not 2.0.0. You can also use .upToNextMajor, .upToNextMinor, or an exact version. This lets you receive safe updates while avoiding breaking changes.

How do I add a package in Xcode?

In Xcode choose File then Add Package Dependencies, paste the package's Git repository URL, pick a version rule, and select which products to add to which targets. Xcode resolves and downloads the package, and from then on you can import it like any framework. Behind the scenes this records the dependency just as the manifest would.