[Pitch][SwiftPM] Opt-in exact matching for version tags that include SemVer build metadata

Hello all,

SwiftPM follows Semantic Versioning 2.0.0 for package versioning. SemVer defines that build metadata (the +... suffix) must be ignored for version precedence, but it can still be useful to distinguish different published artifacts that share the same precedence (e.g. 1.0.0+debug vs 1.0.0+release).

Today, SwiftPM cannot reliably pin a dependency to a specific tag when multiple tags differ only by build metadata. This has shown up in user reports such as:

Motivation / Use cases

Some valid workflows that benefit from metadata-distinct tags:

  • Debug/hardened variants of the same release, especially for prebuilt binaries (e.g. XCFrameworks).
    Example: publish 1.0.0+debug with additional checks/assertions alongside 1.0.0 and allow consumers to pin to the intended artifact for testing.

  • Downstream repackaging / mirroring with provenance (forks, vendor patches, internal compliance builds).
    Example: a downstream publisher republishes upstream 1.0.0 but needs to signal extra information without changing SemVer precedence—such as a vendor patch, compliance status, or internal build provenance. They can publish tags like 1.0.0+customfix, 1.0.0+vendor.1, or 1.0.0+corp.20250324, and consumers can pin to that exact downstream variant when desired.

Proposed solution

Keep SemVer precedence unchanged, but add an opt-in literal exact match mode for version identifiers that includes build metadata. This would allow users to pin to a specific published variant (e.g. 1.0.0+debug) by matching the full version string, while keeping range requirements precedence-based.

  • Keep existing .exact("...") behavior unchanged for compatibility (semantic exact match).

  • Add a new API for literal exact matching, including build metadata, e.g.:

.package(url: "...", .exactLiteral("1.0.0+debug")) // For URL(SCM)-based dependencies

.package(id: "scope.name", .exactLiteral("1.0.0+debug")) // For registry-based dependencies

Semantics:

  • .exact(...) (existing): semantic exact match (current behavior).
  • .exactLiteral(...) (new): candidate must match the tag/version string literally, including build metadata.
  • Range requirements (from, upToNextMajor, etc.) remain precedence-based and unchanged.

This approach is:

  • Non-breaking (existing manifests behave exactly as today).
  • Opt-in for users who need metadata-aware pinning.
  • SemVer-consistent (no change to precedence/ordering rules).

I’d appreciate feedback on:

  • whether the API shape (.exactLiteral) is appropriate or if there are better alternatives.
  • any edge cases or scenarios I may have overlooked.

Thanks!

Anticipated questions

  • Q: Isn't current git hash based exact mechanism enough?
    A: It is enough for strict reproducibility, but not for human-readable variant intent and policy workflows. Metadata-aware exact matching gives a stable, explicit selector at manifest level. Also, this proposal applies to help with registry-based workflows, not just git.

  • Q: Why not just publish a new patch version instead of 1.0.0+vendor.1?
    A: Patch version implies upstream API/behavior progression. In downstream mirroring/repackaging, teams often want to preserve upstream SemVer compatibility while attaching provenance.

  • Q: Does this violate SemVer since build metadata is ignored for precedence?
    A: No. Precedence and range behavior remain unchanged. The proposal only adds opt-in literal exact matching semantics.

  • Q: Will this break existing manifests or resolver behavior?
    A: No, if introduced as a new API (e.g. .exactLiteral(...)) while keeping current .exact(...) behavior unchanged.

3 Likes