Skip to content
C.W.K.
Lesson 02 of 05 · published

A Path Package Is Not a Published Package

~13 min · packaging, distribution, swift, trade-offs

Level 0Loose Parts
0 XP0/48 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

The Word That Covers Two Opposite Products

The previous track refused a package. This track accepts one. If those two sentences use the word the same way, one of the tracks is lying.

They do not. A published package is a product sold to consumers you do not control: it lives on a registry, it carries a version, it is fetched at install time, and two consumers pinning different versions is a supported state. That is the isolation product. That is what the family declined, and still declines, for every language.

A path package is a compiler instruction. It says: build the package in this directory beside me, from whatever the directory holds right now, and let me link the products I name. Its targets are still separate modules; what the path removes is the version, not the module boundaries. There is no version. There is no publish step. There is no registry account. The directory is the sibling working tree the family already lives in. Resolving it costs what vendoring costs to set up — a line in a manifest the consumer already had — and nothing to keep.

What Isolation Would Have Added Here

Walk the published-package charges against this family and they are still charges, not features. A publish step in every Swift change. A version number that has to be reasoned about and bumped. The possibility — now made legitimate — of two phone apps compiling different revisions of the shared types. The last one is the same sharp edge the original record named: skew as a supported feature, inside the repository that exists to make skew a bug.

A path dependency cannot express that skew as a choice. It points at a tree, not at a tag, so there is no line in which one consumer asks to stay on an older revision. Two builds on different days can still compile different trees, because the directory moved between them — the last lesson of this track is about exactly that cost — but no consumer can decide to stay behind. That is not a limitation the family is patiently enduring. It is the property they were buying.

Do not let one word hide two products. "We started packaging" is the identity decay the reversal lesson warned about, applied to a vocabulary collision. If you cannot say in one sentence which product you accepted — isolation across time and space, or a build input with no version — you have not made a decision. You have changed the label on the old one.

Still No Registry

The previous track's spine doctrine looked, for a moment, like a casualty: a consumer now lists a package. Read the list. The package is a relative path to a sibling that is already on the machine. A cold checkout of the consumer alone can no longer build the Swift half. That part is new, and the previous track's third lesson says so: the vendored half still builds from the consumer's checkout alone, while the Swift half now needs the kit beside it. What made the trade acceptable is that the kit repository was already a sibling the family layout assumed, and the drift check already depended on it. (Where that sibling is missing, the check now fails on a fleet Mac and skips only off the fleet; track 4.) The path package did not add a network. It named a directory the family layout already assumed.

What would break the spine is a registry. A tag. A promise that the bytes can be fetched later. None of those arrived. The next lesson is why the compiler needed to see the graph at all; this one is only the refusal to misname it.

Code

A path dependency is a directory, not a version·swift
// In the consumer's package manifest. No version. No registry.
// The path is relative because every repo in this family already
// lives as a sibling of every other repo.
.package(path: "../the-kit/CwkKit")

// Then, per target, take only the product you need. A phone that
// never hosts a web view must not link a web product to get a
// path fence — that is the membership test, applied to linkage.
.product(name: "CwkKitCore", package: "CwkKit")

// Contrast — the product that was refused. Same word, opposite
// thing. Uncommented it would be a lie about this family:
//
// .package(url: "https://example.invalid/the-kit.git", from: "1.0.0")
//
// That line buys isolation: a pin, a fetch, a day when consumer A
// is on 1.2 and consumer B is on 1.4. The path line cannot say
// that. Its inability to say that is the feature.

External links

Exercise

In a codebase you know, find every place the word 'package' is used for a dependency. Split the list into isolation products (registry, version, pin, fetch) and unversioned build inputs (path, workspace, monorepo member). If any row is ambiguous, write the sentence that would disambiguate it — which of the two products that row actually is.
Hint
The tell is usually the presence of a version. A version means isolation was for sale. A path means the build needed the source beside it and nobody wanted to sell isolation.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.