Swift Package Registry
LPM implements SE-0292, the Swift Package Registry standard. Swift Package Manager resolves and fetches LPM packages natively — no plugins, no workarounds.
Setup
One command configures everything — registry scope, authentication, and the SPM signing trust policy:
lpm swift-registry
This runs four steps and is fail-loud — any of them returning a non-success exit aborts the command instead of silently completing with broken signing:
- Registers
lpmdevscope with SPM pointing tohttps://lpm.dev/api/swift-registry. - Logs in with your LPM token (stored in keychain).
- Downloads LPM's CMS signing certificate to
~/.swiftpm/security/trusted-root-certs/lpm.der. - Writes a scope override into
~/.swiftpm/configuration/registries.jsonso SPM accepts packages signed by LPM's self-signed certificate.
Prerequisites: You must be logged in (lpm login) and have Swift 5.9+ installed.
Manual Setup
If you prefer to configure manually, you have to mirror both sides — the cert in the trust folder and the scope override in registries.json:
# 1. Set registry scope
swift package-registry set --scope lpmdev https://lpm.dev/api/swift-registry
# 2. Authenticate
swift package-registry login https://lpm.dev/api/swift-registry --token YOUR_LPM_TOKEN --no-confirm
# 3. Download LPM's CMS signing certificate
mkdir -p ~/.swiftpm/security/trusted-root-certs
curl -o ~/.swiftpm/security/trusted-root-certs/lpm.der https://lpm.dev/api/swift-registry/certificate
# 4. Write the lpmdev scope override (silentAllow on untrusted-signer)
# LPM's cert is self-signed (not a CA), so it cannot be added to SPM's
# root trust store; the scope override tells SPM to accept the cert
# for the lpmdev scope without requiring a CA chain.
mkdir -p ~/.swiftpm/configuration
# (`lpm swift-registry` produces this file with the right shape — manual
# editors should run the CLI once and inspect the resulting JSON, then
# replicate it on other machines.)
Installing Packages
lpm install @lpm.dev/acme.swift-logger
The CLI automatically:
- Fetches the package metadata (version, product name)
- Edits your
Package.swift— adds the dependency and product to your target - Runs
swift package resolve
If your project has multiple targets, the CLI prompts which one to add the dependency to. Use --yes to skip prompts and pick the first target.
What it looks like in Package.swift
After lpm install, your manifest looks like:
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "MyApp",
platforms: [.macOS(.v12), .iOS(.v15)],
dependencies: [
.package(id: "lpmdev.acme-swift-logger", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.60.0"),
],
targets: [
.target(name: "MyApp", dependencies: [
.product(name: "Logger", package: "lpmdev.acme-swift-logger"),
.product(name: "NIOCore", package: "swift-nio"),
]),
]
)
You can also edit Package.swift manually — the .package(id:) syntax is standard SE-0292.
Package Identity
LPM package names map to SE-0292 identifiers:
| LPM Name | SE-0292 Identifier |
|---|---|
@lpm.dev/acme.swift-logger | lpmdev.acme-swift-logger |
@lpm.dev/acme.design-system | lpmdev.acme-design-system |
The pattern is: lpmdev.{owner}-{package-name}. The lpmdev scope tells SPM to fetch from the LPM registry.
Package Signing
All Swift packages published to LPM are signed with a CMS detached signature (ECDSA P-256, SHA-256). Two things to be precise about — what the signature buys you, and what it doesn't:
What the current trust model gives you
- Detached package integrity. SPM verifies the CMS signature against the source archive bytes on every install. A tampered tarball fails the integrity check before any code runs.
- Transport authenticity via HTTPS. The lpm.dev origin is the trust anchor for "this package came from LPM" — your system's CA chain authenticates the connection that carried the cert and the tarballs.
What it does NOT give you (yet)
- Trusted signer identity. LPM's signing cert is self-signed, non-CA, and cannot be added to SPM's root trust store.
lpm swift-registrywrites asilentAllowscope override for thelpmdevscope intoregistries.json, which tells SPM to accept the signature without a chain to a system trust root. The CMS bytes are verified, but the question "is this signer who they say they are?" is anchored in HTTPS to lpm.dev, not in a cert chain. - Per-publisher attribution. Today the signer is the LPM registry itself, not the package author — the signature attests "this came from LPM" rather than "this came from author X". Author-specific provenance (e.g., Sigstore) is a separate, future track.
If you remove the certificate or skip step 4 of the manual setup, SPM rejects every signed LPM package as untrusted-signer. To opt out of signature checking entirely (not recommended):
swift package resolve --resolver-signing-entity-checking warn
Transitive Dependencies
LPM packages can depend on other LPM packages. SPM resolves the entire dependency chain through the registry:
MyApp
└── @lpm.dev/acme.swift-network (LPM)
├── @lpm.dev/acme.swift-logger (LPM) ← resolved via registry
└── swift-nio (GitHub)
LPM packages can also depend on regular GitHub-hosted Swift packages. SPM handles both sources in a single resolution pass.
Install vs Source Delivery
lpm install | lpm add | |
|---|---|---|
| Use for | Library dependencies | UI components, templates |
| Managed by | SPM's resolver | You (code copied into your project) |
| Updates | swift package update | Re-run lpm add |
| Transitive deps | Automatic | Manual |
| Customization | Use as-is | Edit freely |
Rule of thumb: If you'd import it, use lpm install. If you'd modify it, use lpm add.
Publishing Swift Packages
Publishing works the same regardless of how consumers install. The CLI auto-detects Swift from Package.swift:
cd my-swift-library
lpm publish
The server automatically:
- Extracts
Package.swiftmetadata (targets, platforms, dependencies) - Creates a zip source archive for SPM
- Signs the archive with LPM's certificate
See Publishing for the full guide.