Skip to content

Swift Package Registry

Avrea runs a Swift package registry that caches public and eligible organization-private Swift packages hosted on GitHub. SwiftPM can resolve semantic-version dependencies as checksummed source archives served from colocated storage instead of running a full git clone for each dependency.

Public package source is shared across Avrea customers. Private package source and metadata remain isolated to the organization that is authorized to access the corresponding GitHub repository.

The registry caches package source, not compiled output. Xcode Compilation Cache reuses compiler results, while Tuist Module Cache substitutes complete prebuilt targets.

Public registry configuration is on by default. SwiftPM and Tuist commands opt into replacing Git dependencies as described below. Private package resolution also requires an explicit opt-in. Both require the Package Manager Cache and Swift Package Registry settings to remain enabled.

Enable private packages for an organization or repository in the console, or via the CLI:

Terminal window
avr settings set cache.swift-private-registry.enabled true

The setting applies to new jobs. A repository-level override takes precedence over the organization setting.

On macOS runners with Xcode 26 or later, Avrea configures the package registry before workflow steps run. When Avrea creates the native registry configuration, it also enables Xcode's source-control-to-registry transformation. Eligible version-based Git dependencies then resolve through the registry. Branch and revision dependencies continue to download through Git.

Xcode Compilation Cache separately reuses compiler output without requiring registry transformation.

If resolution fails with invalid package type registry <identity>, check the swift-tools-version declaration in every local root package loaded by the Xcode workspace. SwiftPM selects the lockfile format using the lowest root tools version. Versions below 5.6 select the legacy format, which cannot store registry dependencies. Update those local manifests to at least 5.6:

Package.swift
// swift-tools-version:5.6

If a branch or revision dependency then reports a missing product, give its dependency declaration an explicit name matching the product's package reference. Registry transformation changes the dependency identity while retaining Git fetching; the explicit name preserves product lookup:

.package(
name: "MetaTextKit",
url: "https://github.com/mastodon/MetaTextKit.git",
branch: "2.2.5-xcode16"
)
// The target's product reference stays unchanged:
.product(name: "MetaTextKit", package: "MetaTextKit")

The same applies to dependencies declared with revision:.

The SwiftPM CLI does not use Xcode's transformation preference. Commands such as tuist install, swift package resolve, and swift build need the --replace-scm-with-registry option to replace eligible GitHub URL dependencies with registry downloads.

Avrea configures its registry as the default before workflow steps run. The same managed configuration is available to native SwiftPM and embedded SwiftPM clients such as Tuist. Normal workflows do not need to run swift package-registry set or associate individual public scopes.

Commit Tuist/Package.resolved and run:

Terminal window
tuist install \
--replace-scm-with-registry \
--force-resolved-versions

--replace-scm-with-registry asks SwiftPM to replace eligible source-control dependencies. --force-resolved-versions uses the committed versions and fails if the manifest and lockfile disagree.

To make replacement part of the Tuist project configuration, pass the SwiftPM option through installOptions:

Tuist.swift
import ProjectDescription
let tuist = Tuist(
fullHandle: "my-organization/my-project",
project: .tuist(
installOptions: .options(
passthroughSwiftPackageManagerArguments: [
"--replace-scm-with-registry"
]
)
)
)

Alternatively, declare a package by registry identity when it must always use the registry:

Tuist/Package.swift
dependencies: [
.package(id: "apple.swift-log", exact: "1.6.4")
]

Direct identities do not fall back to Git. Avrea's managed default resolves eligible public identities. Resolution fails if customer-managed configuration does not provide a registry for the identity.

The following combinations were validated with tuist install on Avrea macOS runners:

Package declarationAdditional configurationResult
Public identity such as apple.swift-log with an exact versionNoneAvrea public registry
Public GitHub URL with an exact semantic versionPass --replace-scm-with-registryAvrea public registry
Public GitHub URL with an exact semantic version, without the replacement optionNoneGit
GitHub URL with branch: "main"NoneGit
GitHub URL with a commit hash in revisionNoneGit
GitHub URL with revision: "1.6.4"NoneGit tag or ref, not a registry version
Eligible private GitHub URL with an exact semantic versionEnable Private Swift Packages and pass --replace-scm-with-registryOrganization-isolated private registry

A dependency graph can mix registry and Git dependencies. Only eligible semantic-version packages move to the registry.

tuist install stores dependency checkouts, registry downloads, extracted source, binary artifacts, plugins, macros, and SwiftPM workspace state under Tuist/.build. It can contain complete private dependency source. The Tuist Module Cache guide shows how to store this state in the repository-scoped GitHub Actions cache and use it in main-branch warming and pull-request jobs.

Package identities map to GitHub repositories. The package at github.com/apple/swift-numerics has the public registry identity apple.swift-numerics. The first time a version is requested, Avrea fetches the tagged source from GitHub, creates a stable source archive, and caches it. Later requests for that version receive the same archive and checksum from colocated storage.

When Private Swift Packages is enabled, eligible private packages can keep their existing https://github.com/{owner}/{repository} declaration. Avrea selects the organization's private mirror behind the scenes. No GitHub or Avrea service credential is added to the runner VM.

Branch and commit requirements, private repositories outside the organization's GitHub App installation, unsupported origins, and packages that cannot be represented by a registry identity continue to use Git.

When a dependency resolves through the registry, Package.resolved records a registry identity and archive checksum instead of a Git URL and commit. If the checked-out lockfile contains eligible Git-form pins, CI may rewrite them in the runner's ephemeral working tree while preserving the selected versions. The committed file is unaffected unless the workflow explicitly persists it.

If workflows diff or hash-key Package.resolved, keep the registry behavior consistent across the repository so pins do not alternate between Git and registry forms. On a developer machine, local SwiftPM can continue resolving the original GitHub URL with the developer's own credentials.

If tooling requires Package.resolved to remain byte-for-byte unchanged during CI, disable registry resolution:

Terminal window
avr settings set cache.swift-registry.enabled false

For a regular Swift package, commit Package.resolved and resolve with:

Terminal window
swift package resolve \
--replace-scm-with-registry \
--force-resolved-versions

For Xcode projects, the strict resolved-version equivalent is xcodebuild -disableAutomaticPackageResolution.

The effect is largest on a fresh runner. Resolving Vapor's 28-package dependency graph produced:

SetupResolve time
Git, no lockfile23s
Registry, no lockfile11s
Git, committed lockfile and --force-resolved-versions12s
Registry, committed lockfile and --force-resolved-versions4s
  • macOS runner with Xcode 26 or later: registry resolution relies on current SwiftPM and Xcode support. Older Xcode versions continue to use Git.
  • GitHub-hosted dependencies: public repositories are eligible. Private packages additionally require Private Swift Packages, an Avrea GitHub App installation that covers the organization, and an available private mirror.
  • Semantic-version requirements: branch and revision dependencies continue to use Git and the workflow's existing credentials.

Avrea preserves a registries.json supplied by the workflow or runner image. This customer-owned file takes precedence over Avrea's managed configuration for the SwiftPM client that reads it. Normal workflows should remove the custom file and use the managed configuration.

If the custom configuration is intentional, associate its default registry and the reserved private scope with Avrea:

Terminal window
swift package-registry set --global \
https://cache.avrea.com:8443/swift
swift package-registry set --global \
--scope avrea-com \
https://cache.avrea.com:8443/swift

The avrea-com association selects Avrea's private package namespace; it does not grant access. Private requests remain subject to the organization setting, GitHub App installation, package mirror, and authorization checks.

Tuist and other embedded SwiftPM clients can read ~/.swiftpm/configuration/registries.json instead of native SwiftPM's ~/Library/org.swift.swiftpm/configuration/registries.json. Keep both files aligned when managing them explicitly.

No registry is configured for a public scope

Section titled “No registry is configured for a public scope”

Avrea's managed default registry handles public scopes without workflow configuration. Check whether the workflow or runner image creates a custom registries.json. Remove that custom configuration, or associate its default registry with Avrea as described in Custom registry configuration.

Confirm that the dependency uses a semantic-version requirement and the SwiftPM or Tuist command includes --replace-scm-with-registry. Branches, commit hashes, and values passed via revision intentionally remain Git dependencies.

SwiftPM warns that the source archive is not signed

Section titled “SwiftPM warns that the source archive is not signed”

Avrea registry archives currently use a stable checksum but are not signed. The runner config treats this as a warning so installation continues. A checksum mismatch remains an error.