Skip to Content
Course content

102: Publishing a Swift Package

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was working on a suite of three different internal apps for a client. Each app had its own slightly different implementation of a "UserSession" manager—the logic for handling JWT tokens, expiration, and refreshing. Every time the backend team changed the token format, I had to manually hunt down the logic in three different repositories, apply the fix, and hope I didn't miss a line of code in the third app. It was a tedious, error-prone loop that felt completely unnecessary. The moment I extracted that logic into a standalone Swift Package and published it to our private GitHub organization, that friction disappeared. I updated the code once, bumped the version, and the apps just requested the update. That's the power of publishing: you stop repeating yourself across projects.

Tagging Your Code for the Public

Before you can let other developers (or your future self) use your package, you need to move it from a local folder on your Mac to a remote repository. Most of us use GitHub or GitLab, and for Swift Package Manager (SPM), the repository URL is the "address" of your code. But simply pushing your code to main isn't enough for a professional package.

If you just point a project to a branch, any change you push to that branch could potentially break every app using your package. We avoid this by using Git tags. A tag acts as a permanent snapshot of your code at a specific moment. When you run git tag -a 1.0.0 -m "Initial release" and push that tag to the server, you've created a stable anchor. Now, when someone adds your package, they aren't just getting "whatever is on main"—they're getting exactly what was in the 1.0.0 release. I've seen far too many developers skip this step, only to accidentally break a production app because they pushed a "quick fix" to main that changed a public function signature.

Navigating Semantic Versioning

You'll notice I used 1.0.0. This isn't arbitrary; it's called Semantic Versioning (SemVer), and in the Swift ecosystem, it's the law of the land. The three numbers represent Major.Minor.Patch. If you're just fixing a typo in a comment or a bug that doesn't change how the functions are called, you bump the Patch (1.0.1). If you add a new feature—like adding a logToConsole() method to a NetworkLogger package—that's a Minor update (1.1.0). But if you rename a public class or delete a method, you've introduced a "breaking change." That requires a Major bump (2.0.0).

SPM relies on this logic. When you set a dependency to "Up to Next Major Version," Xcode handles the updates for you. It knows it can safely grab 1.1.0 or 1.0.1, but it will never automatically jump to 2.0.0 because it knows your code might stop compiling. It's a safety net that allows you to iterate on your utility libraries without terrifying the people using them.

Making Your Package Discoverable

Once your code is pushed and tagged, the actual "publishing" part is surprisingly simple because SPM is decentralized. There is no "App Store" for packages; the Git repository is the distribution point. To let someone else use your NetworkLogger, you simply provide them with the HTTPS URL of your repository.

When they add this URL in Xcode's "Package Dependencies" section, Xcode looks at the tags on the remote repo, finds the latest version that matches the requested range, and clones that specific snapshot into the project's build folder. I always recommend adding a clear README.md to the root of your package. Since there's no centralized marketplace, your README is your documentation, your marketing, and your user manual all rolled into one. If I can't figure out how to initialize your package within thirty seconds of reading the README, I'm probably going to look for a different library.




📋 Practical Task

Publishing the "CurrencyFormatter" Utility

Now it's your turn to move from local development to a published state. You will create a small utility package that handles currency formatting and make it available for use in a separate project.

  • Create the Package: Build a Swift Package named CurrencyFormatter with a public function format(amount: Double, code: String) -> String that returns a formatted currency string (e.g., "$1,200.00").
  • Host the Code: Initialize a Git repository locally, create a public repository on GitHub (or a similar service), and push your code to the main branch.
  • Version the Release: Use the terminal to create a git tag 1.0.0 and push that tag to your remote repository.
  • Verify Integration: Create a brand new, empty Xcode Project. Add your CurrencyFormatter package using its remote URL, specifying the version 1.0.0. Call the formatting function within the project to ensure the dependency is resolving correctly.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.