Turning reusable Swift code into a shareable package is straightforward with Swift Package Manager. This guide walks through creating a package, defining its manifest, adding tests, and publishing it for others to consume.
Creating a Swift package is the cleanest way to share reusable code, whether across your own apps or with the wider community.
A package encapsulates a focused piece of functionality behind a stable interface. That makes it easier to test, version, and reuse without copy-pasting files between projects.
Internally, teams use packages to split a monolithic app into feature modules. Externally, developers publish packages so others can add them with a single URL.
The good news is that the tooling is native. Swift Package Manager can scaffold, build, and test a package from the command line or inside Xcode, with no extra tools required.
Before you start, make sure you have Xcode installed, since it bundles the Swift toolchain and the swift command-line interface you will use.
The fastest way to start is from the command line. Create an empty folder for your package, give it a clear name, and run the initializer inside it.
Run swift package init with the library type to generate a library package skeleton. SPM creates a Sources folder, a Tests folder, and a Package.swift manifest.
The generated structure follows convention: your source code lives under Sources with a subfolder named after your target, and your tests live under Tests.
Alternatively, you can create a package in Xcode with File then New then Package, which produces the same layout.
Once scaffolded, open the folder in Xcode by double-clicking Package.swift, or open it in your editor of choice. You now have a working, if empty, Swift package ready to fill with real code.
Package.swift is the heart of your package. It is written in Swift and describes the package's name, products, targets, and dependencies.
The products array declares what consumers can import; for a reusable module you expose a library product. The targets array declares the actual build units, including your main target and its test target.
At the top of the manifest sits a special comment, the swift-tools-version, which tells SPM the minimum toolchain your package requires. Do not delete it.
If your package supports specific platforms, add a platforms entry with minimum deployment versions for iOS, macOS, and any others you target.
Edit the name and product names to match your library. Keep the manifest tidy; because it is real Swift, mistakes here surface as compile errors when SPM evaluates the file.
Now add the actual functionality inside the Sources folder under your target's directory. Replace the placeholder file with meaningful Swift types.
Mark anything you want consumers to use with the public access level. By default, Swift symbols are internal and invisible outside the module, so forgetting public is a common early mistake.
Keep your public interface small and intentional. A tight surface area is easier to maintain and version without breaking users.
Group related types into files, and consider organizing larger packages into multiple targets if the code naturally splits into layers.
Build frequently with swift build from the command line, or Command plus B in Xcode, to catch errors early. A clean build means your module compiles and is ready for testing.
A package without tests is hard to trust, and SPM makes testing a first-class feature. The scaffold already created a Tests folder with a starter test target.
Write tests using Apple's testing tools; you can use the XCTest framework or Swift's newer testing framework, importing your package as a module inside the test file.
Because the test target depends on your library target in the manifest, you can import your module and exercise its public API directly.
Run the full suite with swift test on the command line, or use the Test navigator in Xcode with Command plus U.
Aim to cover the public behavior consumers rely on. Passing tests give you the confidence to tag releases and let others adopt your package without fear of regressions.
Before publishing, invest in the basics that make a package usable by others. Start with a clear README that explains what the package does and how to add it.
Include a short code example showing the primary use case. Developers decide whether to adopt a package within seconds of reading the README, so make it count.
Add a LICENSE file. If you intend the package to be open source, choose a recognized license so consumers know their rights. Without a license, others may be legally unable to use your code.
Consider adding inline documentation comments to your public API, which Xcode surfaces in Quick Help and can compile into a documentation site.
These files cost little effort but dramatically increase the odds that someone actually uses what you built.
Publishing a Swift package does not require a central registry or an account. You simply host the repository on a Git service and tag a version.
Push your package to a remote repository, such as GitHub. Then create a version tag that follows semantic versioning, for example a tag like 1.0.0.
SPM discovers versions from Git tags. When a consumer requests 'up to next major,' SPM reads your tags to find compatible releases.
Push the tag to the remote so it is publicly visible. From that moment, anyone can add your package using its repository URL and select the version rule they want.
For future releases, make your changes, run tests, and create a new semantic-version tag. Increment the major number for breaking changes so existing users are not silently broken.
Keep versioning disciplined. Semantic versioning is a promise to your users: patch for fixes, minor for additive features, major for breaking changes.
Maintain a changelog so consumers can see what changed between releases. Combined with clear tags, this makes upgrades far less stressful.
Be mindful of your own dependencies. Every dependency you add becomes a dependency for everyone who uses your package, so keep the tree lean.
Remember the boundaries of what a package is. A package is reusable Swift code and its build configuration; it is not a full app. Building and shipping an app to the App Store still requires Xcode and the Apple Developer Program.
Finally, a Swift package is inherently native Swift. It is not the same as cross-platform or low-code output, which is exactly what you want when building for Apple platforms.
Create a folder, run swift package init with the library type, or use File then New then Package in Xcode. This scaffolds Sources, Tests, and a Package.swift manifest.
Swift symbols are internal by default. Mark the types and functions you want to expose with the public access level so they are visible outside the module.
Host the repository on a Git service and push a semantic-version tag such as 1.0.0. SPM reads Git tags to discover releases; there is no central registry to register with.
Yes, if you want others to use your package. Without a recognized license, other developers may be legally unable to depend on your code.
No. A package holds reusable code and build configuration. Building and submitting a full app still requires Xcode and the Apple Developer Program.