Use from: for most Swift package dependencies. It accepts updates up to the next major version, which keeps you on compatible releases. Use a range when you need a tighter window, exact with a clear reason, and avoid branch and revision in anything you ship, because they bypass version meaning entirely.
The five requirement forms
The Swift Package Manager documentation lists five ways to declare a dependency in Package.swift. Three are version based and two point at source control.
| Form | What it accepts | Updates arrive |
|---|---|---|
from: "1.2.3" | 1.2.3 up to, not including, 2.0.0 | Yes, within the major version |
.exact("1.2.3") | That one version | No |
Range such as "1.2.3"..<"1.2.6" | Versions inside the range | Yes, inside the window |
.branch("develop") | Whatever is at the branch tip | Every change on the branch |
.revision("e74b07...") | One commit hash | No |
The documentation calls from: the recommended form and says exact is not recommended because it can cause conflicts when several packages depend on the same package.
Security trade offs of each
from. You receive patch releases automatically on the next resolve, which is how most security fixes reach you. The risk is that a compatible looking release still changes behaviour, so keep your resolved versions under review.
exact. You are stable, but you also stay on a vulnerable version until someone edits the manifest. Pinning is a decision to own the patching, not a way to avoid it.
range. Useful when a later minor release broke something. Revisit the upper bound on a schedule, since a forgotten ceiling quietly blocks fixes.
branch. The dependency changes whenever the branch does. The docs note a package with a branch requirement cannot be depended on by packages using version requirements. For security, the point is simpler: you cannot say which code you shipped from the requirement alone.
revision. Fixed and reproducible, but you get no updates. The documentation says to limit it to exceptional cases.
A sensible default
- Declare dependencies with
from:at the version you tested. - Commit the resolved file your build produces so every machine and CI run uses the same versions.
- Update on a regular cadence, and sooner when an advisory affects a package you use.
- Treat any branch or revision requirement as a temporary measure with an owner and a date.
- Keep a list of what you ship. Listing every dependency in an iOS app shows how.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how direct and transitive packages appear in one inventory.
Safeguard builds an SBOM and scans your dependencies for known vulnerabilities, and you can run a free scan at gold.safeguard.sh/scan to see what your own project pulls in.
Quick check
Is exact pinning safer than from?
Not automatically. It prevents surprise changes, but it also blocks security fixes until you edit the manifest. Pin when you will own the update schedule.
Can I use a branch in a production app?
You can, but the requirement no longer tells you which code you shipped. Prefer a tagged version or a revision with a documented reason.
Sources
Last reviewed: 19 October 2026.