Commit Package.resolved for an app or any top-level Swift project, because it records the exact dependency versions your builds use. For a library, committing it does not pin versions for the people who depend on you, since SwiftPM ignores a dependency's own Package.resolved during resolution.
What the file is
The Swift Package Manager documentation says the package manager records the result of dependency resolution in a file named Package.resolved at the top level of the package. When you resolve dependencies for the top-level (leaf) package, the file acts as a cache of the versions of the dependencies.
For an app that adds a package inside Xcode, the file sits inside the project or workspace bundle rather than next to a Package.swift.
Apps versus libraries
| Project type | Commit Package.resolved | Why |
|---|---|---|
| App or tool (leaf package) | Yes | Gives every build the same versions |
| Library used by other projects | Optional | Your consumers ignore it, they get the latest eligible versions |
| Container or CI build | Pass it in | The docs suggest resolving locally and passing it to a build |
The documentation states that the file does not provide dependency pinning for libraries or packages used as dependencies of other Swift projects. If your package has the file checked in, those versions are ignored by a package that depends on it.
What happens without it
If no Package.resolved exists, each user or build system resolves versions separately, only updating when they run the update command, and new users start with the latest eligible version of each dependency. Two developers can then build different dependency sets from the same Package.swift.
Forcing the recorded versions
swift package resolve --force-resolved-versions
The docs say this makes the resolve command use the dependencies written into Package.resolved. Use it in CI so a build fails rather than quietly resolving something new.
To move forward on purpose, run the update command. It moves dependencies to the latest eligible versions and rewrites Package.resolved, and you review that diff in a pull request.
What a scanner should read
The recorded file gives exact versions, which is what advisory matching needs. A scan that reads only Package.swift sees version ranges, not the versions that were built. GitHub's dependency graph lists Package.resolved as its recommended file for Swift, which fits the same logic.
Try it yourself
Click through it at your own pace, or open it full screen.
Check how an exact resolved version differs from a declared range in the inventory.
Quick check
Does my library's Package.resolved protect my users?
No. The SwiftPM docs say it is ignored when your package is resolved as a dependency of another project.
How do I stop CI from picking up newer versions?
Commit Package.resolved and run resolve with the force resolved versions option so the build uses what is recorded.
Safeguard's SBOM and dependency scanning builds a component inventory from project files like these and checks it against known advisories. Try the free scan.
Sources
- SwiftPM: Resolving and updating dependencies
- Swift PackageDescription API: Package Dependency
- Dependency graph supported package ecosystems
Last reviewed: 19 October 2026.