Swift Package Manager
|
This section documents the Swift 6 language mode as shipped by Swift 6.3, as published in The Swift Programming Language at docs.swift.org, which is the reference these pages are written and verified against. 6.4-beta-only features are always flagged as such — never presented as baseline. This content was generated with the assistance of AI and should be verified against docs.swift.org before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Swift Package Manager (SwiftPM) is Swift’s built-in build system and dependency manager — a Package.swift
manifest, written in Swift itself, replaces the project files a separate IDE would otherwise own, and the same
manifest drives swift build, Xcode, and CI identically on every platform Swift supports.
Package.swift and PackageDescription
// swift-tools-version: 6.1
import PackageDescription
let package = Package(
name: "WeatherKit",
platforms: [.macOS(.v14), .iOS(.v17)], // omit entirely for a platform-agnostic package
products: [
.library(name: "WeatherKit", targets: ["WeatherKit"]),
.executable(name: "weather-cli", targets: ["WeatherCLI"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.5.0"),
.package(path: "../SharedModels") // a sibling checkout, not a remote fetch
],
targets: [
.target(
name: "WeatherKit",
dependencies: ["SharedModels"],
resources: [.process("Resources")],
swiftSettings: [.swiftLanguageMode(.v6)]
),
.executableTarget(
name: "WeatherCLI",
dependencies: [
"WeatherKit",
.product(name: "ArgumentParser", package: "swift-argument-parser")
]
),
.testTarget(name: "WeatherKitTests", dependencies: ["WeatherKit"])
]
)
The leading // swift-tools-version: comment (see
Getting Started) selects which version of the
PackageDescription API the manifest itself is parsed against — a manifest that uses a Swift 6.1-only API
(such as swiftSettings traits added in that release) needs at least that tools version, independent of which
language mode the package’s targets compile in. Package(name:platforms:products:dependencies:targets:) is the
manifest’s single top-level value; every other declaration is a static factory method on Target, Product or
Package.Dependency.
Products, Targets and Test Targets
A product is what a package exposes to other packages or to a build system outside SwiftPM: .library
(a set of targets consumers can import) or .executable (a runnable binary). A target is a buildable unit
of source, one directory under Sources/<TargetName>/ (or Tests/<TargetName>/ for a test target) by
convention:
| Target kind | Purpose |
|---|---|
|
Ordinary library code, importable by other targets in the same package. |
|
A |
|
Swift Testing or XCTest code, run with |
|
A macro-plugin target built as a separate compiler-plugin executable — see Macros. |
|
Wraps a C library already installed on the system rather than one SwiftPM builds — see Interoperability with C, Objective-C and C++. |
|
A build-tool or command plugin, declared with a |
Dependencies, Version Rules and Conditions
dependencies: [
.package(url: "https://github.com/apple/swift-collections.git", from: "1.1.0"), // upToNextMajor
.package(url: "https://github.com/apple/swift-algorithms.git", .upToNextMinor(from: "1.2.0")),
.package(url: "https://github.com/apple/swift-syntax.git", exact: "600.0.1"),
.package(url: "https://github.com/apple/swift-log.git", branch: "main"),
.package(id: "apple.swift-numerics", from: "1.0.0"), // resolved via a package registry, not a URL
.package(path: "../SharedModels") // a local, unversioned checkout
]
from: resolves to the next major version below the following one (SwiftPM’s default, equivalent to
.upToNextMajor(from:)); .upToNextMinor(from:) and exact: narrow that further; branch:/revision: pin a
non-tagged commit, useful during development but not for a published package. A conditional dependency on a
target scopes when it applies:
.target(
name: "App",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.target(name: "LinuxOnlyHelpers", condition: .when(platforms: [.linux]))
]
)
.when(platforms:) and .when(configuration:) (.debug/.release) restrict a dependency, and equally a
resources: entry (.process, which lets SwiftPM transform the file, or .copy, verbatim) or a linkerSetting/
swiftSetting, to only the platforms or build configurations where it applies.
Building, Running, Testing and Publishing
swift build # debug build of every target
swift build -c release # release build
swift run weather-cli --city Madrid # build (if needed) and run an executable target
swift test # run every test target
swift test --filter WeatherKitTests/parsesForecast
swift package resolve # resolve dependencies without building
swift package update # re-resolve to the newest versions the rules allow
swift package generate-documentation # DocC, via the swift-docc-plugin -- see
# xref:programming-languages/swift/build-and-tooling.adoc[Build and Tooling]
swift package plugin --list # discover build-tool/command plugins available to this package
Package.resolved is the lockfile SwiftPM writes after resolution: it pins every dependency (direct and
transitive) to an exact version, and committing it is what makes a package’s build reproducible across machines
and CI runs the same way a lockfile does in other ecosystems — swift package update is the explicit,
deliberate way to move it forward. A local dependency (.package(path:)) is a sibling directory checked out
on disk, with no version at all, used for developing two packages together; a registry dependency
(.package(id:)) resolves against a Swift package registry (SE-0292) by package identifier rather than a Git
URL, which is how a private or corporate registry can host packages without exposing their source location.
The package access level (see Access Control) exists
specifically for this multi-target shape: a symbol marked package is visible to every target within the same
package but invisible outside it, which is the boundary SwiftPM’s own target graph is built around.
swift-format integration comes from the swift-format build-tool plugin (declared as a dependency on
https://github.com/apple/swift-format), which lets swift package plugin --list (or an IDE’s plugin menu)
lint or reformat every target’s sources using the package’s own .swift-format configuration — see
Build and Tooling for swift-format outside SwiftPM.
Publishing
Publishing a package is, at minimum, tagging a commit with a semantic-versioned Git tag (git tag 1.2.0) that
consumers' from:/upToNextMajor rules resolve against — there is no separate build/upload step for a
Git-hosted package. Publishing to a Swift package registry instead (SE-0391) additionally requires
swift package-registry publish, which packages and signs a release and uploads it to the registry’s API rather
than relying on Git hosting at all.
For the common public case — a package hosted on GitHub (or any Git host) and resolved by consumers via
from:/upToNextMajor, as shown throughout this page — no registry account is needed at all: pushing a semver
Git tag is sufficient, and that tag is immediately resolvable by anyone with the repository’s URL. A private or
corporate Swift package registry is the exception: publishing to one does require an account on that registry
and an auth token, supplied via swift package-registry login <url> --token <TOKEN> before
swift package-registry publish can authenticate.
A GitHub Actions release workflow for the common Git-hosted case needs no secrets at all — it only has to validate the package and turn the pushed tag into a GitHub Release:
name: build
on:
push:
tags: [ 'v*' ]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- run: swift build
- run: swift test
- name: Draft a GitHub Release from the tag
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
For an Objective-C library, see also Build and Tooling for publishing via CocoaPods.
A package’s products sit at the top of the graph and are the only thing a consumer sees; internal targets (and the test target, which is never part of a product) form the dependency graph beneath them that SwiftPM actually compiles.
See Also
-
Access Control — the
packageaccess level in full. -
Macros — macro-plugin targets and
CompilerPlugin. -
Interoperability with C, Objective-C and C++ —
systemLibrarytargets wrapping a C library. -
Build and Tooling —
swiftcflags, cross-platform builds, andswift-formatoutside SwiftPM. -
Testing — writing what a
.testTargetruns.