All articles
iOS13 min read

How to Build and Publish Swift Packages: Turn Your Code into Reusable Libraries (2025 Edition)

Transform your copy-paste code into professional Swift libraries. Complete guide to package creation, testing, versioning, and publishing…

K
Karan Pal
Author
Image generated by AI
Image generated by AI

🎯 Introduction

Every iOS developer has been there. You’re deep into a new project and suddenly think, “Wait, didn’t I already write this date formatter like three projects ago?”

So what do you do? You open up some dusty old repo, scroll through folders, copy the code, paste it in, maybe tweak it a little… Fast-forward six months, and now you’ve got five slightly different versions of the same extension scattered across your codebase. 🤦‍♂️

Here’s the thing: You’re not just copying code — you’re accidentally building libraries. You just haven’t packaged them yet.

That string extension you’ve duplicated four times? That’s a library waiting to happen. Those reusable UI components? Swift package material. Even that network manager you’ve perfected over time? Could be helping hundreds of other devs.

📚 This Complete Swift Package Series

This is Part 1 of a 3-part series that’ll turn your scattered snippets into powerful, professional Swift libraries:

By the end of this series, you won’t just write better Swift — you’ll build libraries that scale across teams, projects, and maybe even your career 🚀

🎯 What We’re Transforming Today

Today’s goal: go from copy-paste developer to package creator. We’re taking that tried-and-true utility code you always reuse — and turning it into your first working Swift package.

We’ll cover:

Ready to stop copying and start creating? Let’s turn your code into a package. 📦

💡 Why Create Swift Packages?

Before we dive into the how, let’s talk about the why. Creating Swift packages is hands-down one of the smartest moves you can make as an iOS developer. Once you experience the benefits, you’ll wonder how you ever lived without them.

🙋‍♂️ Personal Benefits: Your Development Life Gets Easier

🔍 No More Code Archaeology

Remember spending 20 minutes digging through old projects just to find that one perfect function? With Swift packages, your best code lives in one clean, organized place. Need your custom date formatter? import Utilities — done.

📦 Consistency Across Projects

Your networking layer shouldn’t look different in every app. With packages, you write it once, perfect it once, and reuse it everywhere. Fix one bug, and all your projects benefit.

⚡ Faster Project Setup

Starting a new iOS project? Skip the copy-paste chaos. Just drop in your Swift packages as dependencies and go. No broken imports. No repeated setup. Just speed.

👔 Professional Benefits: Level Up Your Career

📂 A GitHub Profile That Actually Impresses

Well-documented, reusable code in package form shows you think like an engineer — not just a coder. It says, “I build systems,” not “I patch features.”

🧠 Proof of Problem-Solving Skills

Each package is a public receipt of your ability to identify recurring problems and solve them elegantly — the exact thing senior engineers and tech leads do.

🌱 Open Source Potential

Even if you start private, many packages eventually grow into open-source tools that help the community — and build your reputation in the process.

👥 Team Benefits: Better Collaboration

🔄 Shared Standards

When your team shares the same packages, you share a consistent architecture. New devs ramp up faster. Patterns are predictable. Everyone speaks the same code language.

🧼 Collective Code Quality

Packages naturally attract more collaboration, reviews, and polish. It’s like having your team continuously refactor and refine your utilities without even trying.

🧯 Reduced Technical Debt

Instead of duplicating variations of the same utility in every repo, you get one clean, tested, well-documented version maintained together.

🧠 The Mindset Shift

This is the real power of Swift packages: You stop writing code just for “this project” and start writing tools for your future self, your team, and your entire ecosystem.

Every package you build is a time-saving investment. Stop rewriting that network layer. Stop duplicating that button style. Package it once, and you’re set — forever.

Ready to make the shift? Let’s look at why Swift Package Manager is the perfect tool to help you get there. 🧰

⚔️ Swift Package Manager vs Alternatives

Now that you’re convinced packages are the way to go, you might be wondering: “Why Swift Package Manager? What about CocoaPods or Carthage?”

Great question! While all three can manage dependencies, SPM has become the clear winner for package creation in 2025. Here’s why:

SPM: Apple’s Official Solution

Native Xcode Integration 🍎 SPM is built right into Xcode. No separate installations, no workspace files, no build phases to configure. When you create a Swift package, Xcode understands it natively. When you want to add it to a project, it’s literally just File → Add Package Dependencies.

Zero Configuration Overhead With CocoaPods, you need Podfiles, workspace files, and sometimes complex build configurations. With SPM? You get a clean Package.swift file that’s actually readable. No Ruby gems to install, no version conflicts to resolve.

Future-Proof Choice Apple is clearly investing in SPM as the long-term solution. New features, better performance, and tighter integration keep coming with each Xcode release. Meanwhile, CocoaPods development has slowed, and Carthage is basically in maintenance mode.

The Reality Check

Here’s the honest truth about dependency management in 2025:

CocoaPods is still widely used, especially in large existing projects, but it’s becoming the “legacy” choice. Great for consuming packages, but creating new ones? SPM is simpler.

Carthage had its moment, but it’s been largely abandoned. Even if you encounter it in existing projects, you probably won’t choose it for new work.

SPM is where the ecosystem is heading. New packages are increasingly SPM-first, and Apple continues to improve tooling around it.

Why This Matters to You

When you create Swift packages, you want them to be as accessible as possible. SPM packages work everywhere without additional setup:

Plus, when you’re building packages for your own use, SPM’s simplicity means you spend time writing code, not configuring build systems.

The Bottom Line

You could create packages using other tools, but why make it harder than it needs to be? SPM gives you the cleanest development experience and the widest compatibility.

_Want a deeper dive into the pros and cons of each approach? I’ve written a detailed comparison of_ **_CocoaPods vs Carthage vs Swift Package Manager (SPM) in 2025_** _that covers real-world scenarios and migration strategies._

**CocoaPods vs Carthage vs Swift Package Manager (SPM) in 2025: Which One Should iOS Devs Use?** _Everything iOS developers need to know about CocoaPods, Carthage, and Swift Package Manager in 2025 — features, pros…_medium.comhttps://medium.com/swift-pal/cocoapods-vs-carthage-vs-swift-package-manager-spm-in-2025-which-one-should-ios-devs-use-82b30253d200

Now that we’ve settled on SPM, let’s get our hands dirty and create your first Swift package!

🛠️ Your First Swift Package (Hands-On)

Alright, enough theory! Time to get our hands dirty and create your first Swift package. We’re going to start with something you probably already have — some utility code that you’ve written before.

Step 1: Identify Your Hidden Library

Before we create anything new, let’s find the perfect candidate in your existing projects. Open up one of your recent iOS projects and look for:

Perfect Package Candidates:

Found something? Great! For this tutorial, I’ll use a common example: a collection of useful String extensions. But follow along with whatever code you’ve identified.

Step 2: Create Your Package

In Xcode:

  1. File → New → Package (yes, it’s that simple!)
  2. Select Multiplatform from the package templates dialog.
  3. Select the Library template.
  4. Choose a name like “MyUtilities” or something specific like “StringExtensions”
  5. Pick a location (I recommend a dedicated “Packages” folder in your development directory)
  6. Hit Create

What You Get: Xcode creates a clean package structure with everything you need:

Step 3: Understanding Package.swift

Open the Package.swift file. This is your package's blueprint, and it's surprisingly readable:

// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "MyUtilities",
    platforms: [
        .iOS(.v17)
        .macOS(.v10_15)
    ],
    products: [
        .library(
            name: "MyUtilities",
            targets: ["MyUtilities"]),
    ],
    dependencies: [
        // External dependencies go here
    ],
    targets: [
        .target(
            name: "MyUtilities",
            dependencies: []),
        .testTarget(
            name: "MyUtilitiesTests",
            dependencies: ["MyUtilities"]),
    ]
)

Key Points:

Step 4: Add Your Code

Now for the fun part! Replace the generated code in Sources/MyUtilities/MyUtilities.swift with your actual utility code:

import Foundation

public extension String {
    /// Removes whitespace and newlines from both ends
    var trimmed: String {
        return self.trimmingCharacters(in: .whitespacesAndNewlines)
    }
    
    /// Checks if string is a valid email format
    var isValidEmail: Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailPred.evaluate(with: self)
    }
    
    /// Capitalizes first letter of each word
    var titleCased: String {
        return self.capitalized
    }
}

public extension Date {
    /// Returns a user-friendly relative time string
    var timeAgo: String {
        let formatter = RelativeDateTimeFormatter()
        formatter.unitsStyle = .full
        return formatter.localizedString(for: self, relativeTo: Date())
    }
}

Important: Notice the public keywords! Without them, your code won't be accessible to projects that import your package.

Step 5: Test It Locally

The easiest way to test your package is to create a test right in the package:

import XCTest
@testable import MyUtilities

final class MyUtilitiesTests: XCTestCase {
    func testStringTrimming() {
        let messyString = "  Hello World  \n"
        XCTAssertEqual(messyString.trimmed, "Hello World")
    }
    
    func testEmailValidation() {
        XCTAssertTrue("test@example.com".isValidEmail)
        XCTAssertFalse("invalid-email".isValidEmail)
    }
    
    func testTitleCase() {
        XCTAssertEqual("hello world".titleCased, "Hello World")
    }
}

Run the tests with Cmd+U — they should pass! 🎉

Step 6: Use It in a Real Project

Now for the moment of truth. Open one of your iOS projects and:

  1. File → Add Package Dependencies
  2. Click “Add Local” and navigate to your package folder
  3. Add the package to your target (main target)
  4. Build your Xcode project (if it fails, restart Xcode)

Then in your code:

import MyUtilities

// In some view controller or SwiftUI view
let email = userInput.trimmed
if !email.isValidEmail {
    showError("Please enter a valid email")
}

It works! You’ve just created and used your first Swift package. No more copy-pasting that email validation logic — it’s now a reusable, testable library.

The Magic Moment

Take a second to appreciate what just happened. That code you wrote once is now available across any project with a single import. When you improve the email validation logic, every project that uses your package gets the improvement automatically.

You’ve officially graduated from copy-paste developer to package creator! 🎓

Next up, let’s talk about organizing your package properly and following best practices that’ll make your future self thank you.

🎯 What You’ve Accomplished

Congratulations! You’ve just created your first Swift package and experienced that magical moment when your scattered utility code becomes a professional, reusable library. You’ve officially graduated from copy-paste developer to package creator! 🎓

In this first part of our series, you’ve learned to:

But we’re just getting started! Creating a basic package is one thing — making it professional, maintainable, and community-ready is where the real value lies.

🚀 What’s Next?

Your package works, but is it professional? In the next article, we’ll transform your basic package into something you’d be proud to show in a job interview:

**Swift Package Best Practices: Structure, Testing & Publishing (2025 Edition)**

We’ll cover:

**Swift Package Best Practices: Structure, Testing & Publishing (2025 Edition)** _Level up your Swift packages with professional structure, comprehensive testing, and proper versioning. Complete guide…_medium.comhttps://medium.com/swift-pal/swift-package-best-practices-structure-testing-publishing-2025-edition-d6d1ef7fce93

📖 Part 3 Preview: Beyond Personal Use

Ready to take your packages to the next level? Part 3 will cover the advanced stuff that separates hobby projects from production-ready libraries:

🎉 Enjoyed this article? Your support means the world to me!

💬 Drop a comment below! I love hearing about your experiences and answering questions

🎬 Subscribe on Youtube and become early subscribers of my channel: https://www.youtube.com/@swift-pal

💼 Let’s connect on LinkedIn for more professional insights: https://www.linkedin.com/in/karan-pal

Happy coding! 🚀

● The newsletter

New articles, straight to your inbox.

No spam, no filler — just new writing on iOS, the web, and AI when it ships. Unsubscribe anytime.

Keep reading