iOS Dependency Managers — SwiftPM, CocoaPods, and Carthage in 2026

Dependency managers simplify and standardize fetching third-party code into your project. Without one, you’d manually copy sources, drop in pre-compiled binaries, or use Git submodules.

  • Swift Package Manager (SwiftPM) is Apple’s first-party tool, integrated into Xcode since 2019. It is now the standard for iOS dependencies.
  • CocoaPods was the most popular iOS dependency manager for years and still has a large library registry, though usage is declining.
  • Carthage is a lightweight alternative with much lower ecosystem momentum than SwiftPM. It can still support existing projects, but it is rarely the right default for new apps.

Dependency Management

Adding dependencies to a project has coordination costs. A package manager automates downloading, building, and resolving the entire dependency graph while minimizing version conflicts.

Semantic Versioning

SemVer uses MAJOR.MINOR.PATCH — increment MAJOR for breaking changes, MINOR for backward-compatible additions, PATCH for bug fixes. SwiftPM and CocoaPods both rely on SemVer for dependency resolution.

Binary Dependencies

Binary-only packages are less portable than source packages. In SwiftPM, binary targets are primarily an Apple-platform distribution mechanism through .xcframework artifacts declared with .binaryTarget in the manifest. Prefer source-based dependencies when possible.

Git Submodules

Git submodules embed one repo inside another. They’re simple but have sharp edges: collaborators must remember git submodule update, they don’t resolve transitive dependencies, and managing rapid co-development across repos is painful. Modern package managers are almost always a better choice.

Swift Package Manager (SwiftPM)

SwiftPM is Apple’s officially supported dependency manager, built into the Swift project. It was introduced in Swift 3.0 (2015) and gained full Xcode integration with Xcode 11 (2019). Today, most popular iOS libraries support SwiftPM as their primary distribution method.

Package Manifest

A Swift package is defined by a Package.swift manifest, using swift-tools-version to specify the tool version:

// swift-tools-version:6.0
import PackageDescription

let package = Package(
  name: "DeckOfPlayingCards",
  platforms: [.iOS(.v17), .macOS(.v14)],
  products: [
    .library(name: "DeckOfPlayingCards", targets: ["DeckOfPlayingCards"])
  ],
  dependencies: [
    .package(url: "https://github.com/apple/example-package-fisheryates.git", from: "2.0.0"),
    .package(url: "https://github.com/apple/example-package-playingcard.git", from: "3.0.0"),
  ],
  targets: [
    .target(
      name: "DeckOfPlayingCards",
      dependencies: ["FisherYates", "PlayingCard"]),
    .testTarget(
      name: "DeckOfPlayingCardsTests",
      dependencies: ["DeckOfPlayingCards"]),
  ]
)

Key modern additions:

  • platforms — declare minimum OS versions explicitly.
  • .binaryTarget — include pre-built .xcframework binaries for proprietary or closed-source dependencies.
  • String-based targets (as above) or use .product(name:, package:) for multi-package disambiguation.

Adding Packages in Xcode

Go to File > Add Package Dependencies…, paste a Git URL, and choose a version rule (exact, up-to-next-minor, range, or branch/commit). Xcode resolves the graph, fetches sources, and integrates the target into your project — no workspace required.

Swift Package Index

The Swift Package Index is a community-run search engine that indexes packages supporting SwiftPM. It shows compatibility badges, test status, and version history to help evaluate quality before adopting a dependency.

CocoaPods

CocoaPods manages dependencies via a Podfile and an auto-generated Xcode workspace. It was the dominant iOS dependency manager from ~2013 to 2020 and still hosts the largest catalog of iOS libraries, but adoption is declining as authors prioritize SwiftPM.

Installation

CocoaPods is written in Ruby. Install it without sudo using Homebrew or RubyGems:

brew install cocoapods
# or
gem install cocoapods --user-install

Usage

Specify dependencies in a Podfile:

platform :ios, '17.0'

target 'MyApp' do
  pod 'Alamofire', '~> 5.5'
  pod 'SwiftLint', '~> 0.55'
end

Run pod install to resolve, fetch, and integrate. Always use the .xcworkspace going forward — never open the .xcodeproj directly.

Pods Directory

Whether to check in Pods/ depends on your team’s workflow. CocoaPods recommends keeping Pods/ under source control because a fresh clone can build without running pod install, but the trade-off is repo size and merge conflicts during updates.

Regardless of that choice, commit both Podfile and Podfile.lock. The lockfile records the resolved pod versions and is the minimum needed for reproducible installs.

Carthage

Carthage took a decentralized approach: declare dependencies in a Cartfile, and Carthage builds them into frameworks or XCFrameworks that you drag into your project. It never modified your Xcode project or created a workspace.

Carthage still exists, but it has far less day-to-day adoption than SwiftPM. Existing projects can keep using it when it is stable for their build, but new projects should start with SwiftPM unless they have a specific binary-framework workflow that Carthage handles better.

Migration from Carthage

  1. Remove Cartfile and Cartfile.resolved.
  2. Add the same packages via File > Add Package Dependencies… in Xcode.
  3. Replace framework import statements — Carthage builds are often compatible as-is.
  4. Delete Carthage/ from your repo.

Which One to Choose

Manager Recommendation
SwiftPM Default for all new projects. Integrated into Xcode, actively maintained by Apple, and supported by virtually every modern library.
CocoaPods Use only if a required library is unavailable via SwiftPM. Plan to migrate when possible.
Carthage Avoid for most new projects. Keep it for existing projects only when the current workflow is stable or you need its framework-oriented build style.