# Using LPM CLI with Swift (/docs/guides/using-with-swift)



The LPM.dev Registry speaks the [SE-0292 Swift Package Registry API](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md), so Swift Package Manager (SPM) can resolve LPM.dev Registry-hosted Swift packages natively. This guide walks through the full setup with LPM CLI: installing a Swift package, and (for authors) publishing one.

## Prerequisites [#prerequisites]

* LPM CLI installed — see [Installation](/docs/installation).
* Swift toolchain installed.
* An lpm.dev account, logged in (`lpm login`).

## One-time SPM integration [#one-time-spm-integration]

```bash
lpm swift-registry
```

This runs an idempotent, fail-loud setup:

1. Logs SPM into the LPM.dev Registry (writes the `swift package-registry` config).
2. Downloads the LPM.dev Registry CMS signing certificate and writes it to `~/.swiftpm/security/trusted-root-certs/lpm.der`.
3. Writes a `lpmdev`-scope override into `~/.swiftpm/configuration/registries.json` (`signing.onUntrustedCertificate = "silentAllow"`) so SPM accepts the self-signed cert without requiring a public-CA chain.

Failures (network, non-2xx from the cert endpoint, truncated body, mkdir/write errors) abort with a clear error rather than silently completing with broken signing — a one-shot `lpm install <swift-pkg>` cannot finish "successfully" with the trust path half-set-up. Re-run with `--force` to refresh the cert (cert rotation, suspicion of corruption, etc.).

> See [Trust model](/docs/packages/swift-package-registry#trust-model) on the concepts page for what the signing posture actually attests to today (detached integrity + HTTPS authenticity) and what it does not (trusted signer identity, per-author attribution).

## Installing a Swift package [#installing-a-swift-package]

Use [`lpm install`](/docs/packages/install) for Swift packages — it edits `Package.swift` and triggers `swift package resolve`:

```bash
lpm install @lpm.dev/owner.swift-pkg
lpm install @lpm.dev/owner.swift-pkg@1.2.0      # specific version
```

Behind the scenes, `Package.swift`'s `dependencies:` and `targets:` arrays get updated with the new package. Cross-target wiring is handled.

> `lpm add` also supports Swift packages today (with `--target&#x60; for SPM-target wiring), but **`lpm install` is the right command** for SPM dependencies — `lpm add` is source-delivery, while Swift packages want registry-resolved deps.

## Publishing a Swift package [#publishing-a-swift-package]

The flow is the same as any other package published to the LPM.dev Registry, plus two Swift-specific requirements:

1. Your project must declare `ecosystem: "swift"` in `lpm.config.json`.
2. The repo must have a valid `Package.swift` at the root.

```bash
lpm publish
```

The publish pipeline:

* Packs the repo into a tarball.
* Generates a `.zip` source archive with the SE-0292-required `{pkgName}-{version}/` top-level wrapper.
* Computes the SHA-256 checksum that SPM expects.
* Generates a CMS-1.0.0 detached signature (ECDSA P-256 / SHA-256) with the LPM.dev Registry signing cert.
* Uploads tarball + zip + signature to lpm.dev.

After publish, SPM clients on any machine that's run `lpm swift-registry` can resolve the package by its LPM.dev Registry identity.

## Identity mapping [#identity-mapping]

LPM.dev Registry packages are named `@lpm.dev/owner.pkg-name`. SE-0292 scopes can't contain dots, so LPM CLI maps them when surfacing to SPM:

| LPM.dev Registry name     | SPM identity            |
| ------------------------- | ----------------------- |
| `@lpm.dev/owner.pkg-name` | `lpmdev.owner_pkg-name` |

The `_` between owner and package name is the unambiguous separator: the LPM.dev Registry forbids `_` in both owner and package name (DB-level), so the boundary is always clear even when either half contains hyphens. You don't need to deal with the SPM identity by hand — LPM CLI's `lpm install` and `lpm swift-registry` commands handle the translation.

## Verifying signatures [#verifying-signatures]

The LPM.dev Registry serves the CMS signing cert at `https://lpm.dev/api/swift-registry/certificate` (DER). `lpm swift-registry` writes the cert and the matching `registries.json` scope override; SPM then verifies the CMS detached signature on every install.

Signatures are surfaced in three places per release:

* The release metadata JSON (base64 CMS).
* The `Digest` HTTP response header on tarball download.
* A comment block in the `Package.swift` manifest response.

If the cert rotates, re-run `lpm swift-registry --force`. Failed `--force` re-downloads are fatal — the CLI will not silently fall back to the stale cert.

For the trust-model rationale (why the cert is self-signed, why SPM uses a `silentAllow` scope override rather than a trust-store entry, what the signature actually attests to), see [Trust model](/docs/packages/swift-package-registry#trust-model).

## Common pitfalls [#common-pitfalls]

* **`lpm add` for Swift is the legacy path.** Use `lpm install` — `add` is source-delivery, not what you want for a runtime SPM dep.
* **`Package.swift` must use the SE-0292 identity** (`lpmdev.owner_pkg-name`), not the LPM.dev Registry-native form. `lpm install` writes it correctly; if you hand-edit, mind the format — the `_` separates owner from package name.
* **Re-run `lpm swift-registry --force` after cert rotation.** A stale local trust store will refuse new signatures. A failing `--force` is fatal — the CLI does not silently keep the stale cert.

## See also [#see-also]

* [`lpm install`](/docs/packages/install) — runtime dependency installer (works for Swift)
* [`lpm swift-registry`](/docs/packages/swift-registry) — SPM setup command
* [SE-0292](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0292-package-registry-service.md) — the upstream protocol spec
