SwiftPM library distribution with binary targets and Swift Package Registry

Hello!

I want to confirm that my understanding of Swift Package Manager library distribution is correct, particularly regarding the Swift Package Registry and binaryTarget publications.

In my understanding, a library in SPM is defined by a Package.swift file that describes how the library builds using target and binaryTarget primitives. These targets are combined into library products, which can be consumed by other SPM packages through the .product(name:, package:) dependency declaration or via Xcode’s “Frameworks and Libraries” at the target level.

As the author of an SPM library, you have three options for hosting the library so that it can be consumed in another SPM package or an Xcode project:

  • Local Package: Have the package exist locally on disk. Such a package can be added to dependencies via .package(path:) or through the "Add Local..." option in Xcode.
  • Git Repository: Push your library to a Git repository hosted on a platform like GitHub or GitLab, using Git tags or branches for versioning. Consumers can access the library over https:// or ssh:// using the .package(url:) declaration or by specifying the URL in the Package Dependencies UI in Xcode.
  • Swift Package Registry: Use a web server that implements the Swift Package Registry's custom HTTP(S) protocol as per the specification. Consumers can set the registry URL using swift package-registry set and declare the dependency using .package(id:).

SPM doesn't support hosting a library over basic HTTP(S) storage using a simple URL-based layout convention. In particular, Swift Package Registry protocol is designed such that listing the package versions happens over {scope}/{name} path and package is further fetched over {scope}/{name}/{version} path which is usually incompatible with a naive HTTP(S) storage layout.

If your SPM library references a binaryTarget, you have two options for storing the XCFramework/.artifactbundle:

  1. Remote Binary Storage: Upload and store the binary at an HTTP(S) location. Authentication for this storage can be handled using a .netrc file or the Keychain (e.g. via security add-internet-password).
  2. Include in Git Repository: Commit the binary directly into the Git repository. This can lead to slower fetch times with each release due to the increased repository size. While you could use Git LFS to work around this issue, it requires additional setup and isn't natively supported by SPM.

Is my understanding of SPM’s library distribution correct? Are there any misconceptions or important details that I've omitted?

I'm not an authority on this subject but your understanding matches mine. My company hosts a public package in a Git Repository with a binaryTarget stored in Google Cloud Storage. And I consume Local Packages when developing apps in XCode, which makes iterations and bug-fixes in package code that bit easier.

I don't have any experience with Swift Package Registries and I'm not aware of any projects aiming to provide a server implementation, but I've not done extensive research into this approach.

Something I have recently researched is authentication for packages with binaryTargets as we'd like to have the option to distribute these to non-public parties. While Git repositories have various kinds of authentication options (provider dependent) it seems that Remote Binary Storage is actually stuck with only basic authentication through netrc using the swift CLI:

I may raise this issue as its own topic but as far as important, subtle details go, I hope it helps.

1 Like