CocoaPods to Swift Package Manager Migration Step-by-step guide for migrating Capacitor iOS projects from CocoaPods to Swift Package Manager. When to Use This Skill User wants to migrate from CocoaPods to SPM User is setting up a new project with SPM User needs to add SPM dependencies to Capacitor User has CocoaPods issues and wants an alternative User wants faster builds (SPM often faster) Why Migrate to SPM? Aspect CocoaPods SPM Build Speed Slower Faster Apple Integration Third-party Native Xcode Ruby Dependency Required None Version Management Podfile.lock Package.resolved Xcodeproj Changes Modifies project Uses workspace Binary Caching Limited Built-in Migration Process Step 1: Analyze Current Dependencies First, identify what you're currently using: cd ios/App cat Podfile pod outdated Common Capacitor pods to migrate:
Podfile (before)
target 'App' do capacitor_pods pod 'Firebase/Analytics' pod 'Firebase/Messaging' pod 'Alamofire' pod 'KeychainAccess' end Step 2: Find SPM Equivalents Most popular libraries support SPM. Use these URLs: Library SPM URL Firebase https://github.com/firebase/firebase-ios-sdk Alamofire https://github.com/Alamofire/Alamofire KeychainAccess https://github.com/kishikawakatsumi/KeychainAccess SDWebImage https://github.com/SDWebImage/SDWebImage SnapKit https://github.com/SnapKit/SnapKit Realm https://github.com/realm/realm-swift Lottie https://github.com/airbnb/lottie-spm Step 3: Clean CocoaPods cd ios/App
Remove CocoaPods integration
pod deintegrate
Remove Podfile.lock and Pods directory
rm -rf Podfile.lock Pods
Remove workspace (we'll use project directly or create new workspace)
rm -rf App.xcworkspace Step 4: Add SPM Dependencies in Xcode Open ios/App/App.xcodeproj in Xcode Select the project in navigator Go to Package Dependencies tab Click + to add package Enter the package URL Choose version rules Select target App Step 5: Update Podfile for Capacitor Core Capacitor still needs CocoaPods for its core. Create minimal Podfile:
ios/App/Podfile
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers' platform :ios , '14.0' use_frameworks ! install ! 'cocoapods' , :disable_input_output_paths => true def capacitor_pods pod 'Capacitor' , :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova' , :path => '../../node_modules/@capacitor/ios' end target 'App' do capacitor_pods
Other plugin pods that don't support SPM yet
end post_install do | installer | assertDeploymentTarget ( installer ) end Then run: cd ios/App && pod install Step 6: Configure Plugin for SPM Support If you're creating a Capacitor plugin with SPM support: Package.swift : // swift-tools-version: 5.9 import PackageDescription let package = Package ( name : "CapacitorNativeBiometric" , platforms : [ . iOS ( . v14 ) ] , products : [ . library ( name : "CapacitorNativeBiometric" , targets : [ "NativeBiometricPlugin" ] ) , ] , dependencies : [ . package ( url : "https://github.com/nicholasalx/capacitor-swift-pm" , from : "6.0.0" ) , ] , targets : [ . target ( name : "NativeBiometricPlugin" , dependencies : [ . product ( name : "Capacitor" , package : "capacitor-swift-pm" ) , . product ( name : "Cordova" , package : "capacitor-swift-pm" ) , ] , path : "ios/Sources/NativeBiometricPlugin" , publicHeadersPath : "include" ) , ] ) Step 7: Xcode Project Structure for SPM ios/ ├── App/ │ ├── App/ │ │ ├── AppDelegate.swift │ │ ├── Info.plist │ │ └── ... │ ├── App.xcodeproj/ │ │ └── project.xcworkspace/ │ │ └── xcshareddata/ │ │ └── swiftpm/ │ │ └── Package.resolved # SPM lock file │ ├── Podfile │ └── Podfile.lock └── ... Hybrid Approach (Recommended) Most Capacitor projects work best with a hybrid approach: Keep in CocoaPods: @capacitor/ios core Capacitor plugins without SPM support Move to SPM: Firebase Third-party libraries Your own Swift packages Example Hybrid Setup Podfile : require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers' platform :ios , '14.0' use_frameworks ! install ! 'cocoapods' , :disable_input_output_paths => true def capacitor_pods pod 'Capacitor' , :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova' , :path => '../../node_modules/@capacitor/ios'
Plugins without SPM support
pod 'CapacitorCamera' , :path => '../../node_modules/@capacitor/camera' end target 'App' do capacitor_pods
NO Firebase here - use SPM instead
- end
- Xcode Package Dependencies
- :
- Firebase iOS SDK
- Any other SPM-compatible libraries
- Common Issues and Solutions
- Issue: Duplicate Symbols
- Cause
-
- Same library in both CocoaPods and SPM
- Solution
- Remove from Podfile if using SPM
Podfile - WRONG
pod 'Firebase/Analytics'
Remove this
Use SPM instead in Xcode
- Issue: Module Not Found
- Cause
-
- SPM package not linked to target
- Solution
- :
- Xcode > Project > Targets > App
- General > Frameworks, Libraries, and Embedded Content
- Add the SPM package product
- Issue: Build Errors After Migration
- Cause
-
- Missing frameworks or wrong imports
- Solution
- Clean and rebuild
Clean derived data
rm -rf ~/Library/Developer/Xcode/DerivedData
Clean build folder in Xcode
Cmd + Shift + K
Rebuild
- bunx cap
- sync
- ios
- cd
- ios/App
- &&
- pod
- install
- Issue: Capacitor Plugin Not Found
- Cause
-
- Plugin needs registration
- Solution
- Ensure plugin is registered in AppDelegate.swift : import Capacitor import YourPlugin @UIApplicationMain class AppDelegate : UIResponder , UIApplicationDelegate { func application ( _ application : UIApplication , didFinishLaunchingWithOptions launchOptions : [ UIApplication . LaunchOptionsKey : Any ] ? ) -> Bool { // Capacitor handles plugin registration automatically return true } } Creating SPM-Compatible Capacitor Plugin Directory Structure my-capacitor-plugin/ ├── Package.swift ├── ios/ │ └── Sources/ │ └── MyPlugin/ │ ├── MyPlugin.swift │ ├── MyPlugin.m # Objc bridge if needed │ └── include/ │ └── MyPlugin.h # Public headers ├── src/ │ ├── index.ts │ ├── definitions.ts │ └── web.ts └── package.json Package.swift Template // swift-tools-version: 5.9 import PackageDescription let package = Package ( name : "CapacitorMyPlugin" , platforms : [ . iOS ( . v14 ) ] , products : [ . library ( name : "CapacitorMyPlugin" , targets : [ "MyPluginPlugin" ] ) , ] , dependencies : [ . package ( url : "https://github.com/nicholasalx/capacitor-swift-pm" , from : "6.0.0" ) , ] , targets : [ . target ( name : "MyPluginPlugin" , dependencies : [ . product ( name : "Capacitor" , package : "capacitor-swift-pm" ) , . product ( name : "Cordova" , package : "capacitor-swift-pm" ) , ] , path : "ios/Sources/MyPlugin" ) , ] ) Plugin Swift Code import Foundation import Capacitor @objc ( MyPlugin ) public class MyPlugin : CAPPlugin , CAPBridgedPlugin { public let identifier = "MyPlugin" public let jsName = "MyPlugin" public let pluginMethods : [ CAPPluginMethod ] = [ CAPPluginMethod ( name : "echo" , returnType : CAPPluginReturnPromise ) , ] @objc func echo ( _ call : CAPPluginCall ) { let value = call . getString ( "value" ) ?? "" call . resolve ( [ "value" : value ] ) } } Migration Checklist List all current CocoaPods dependencies Identify SPM equivalents for each Run pod deintegrate Add SPM packages in Xcode Create minimal Podfile for Capacitor core Run pod install Clean derived data Build and test Commit Package.resolved to git Update CI/CD scripts if needed Resources Swift Package Manager Documentation: https://swift.org/package-manager Capacitor iOS Documentation: https://capacitorjs.com/docs/ios CocoaPods to SPM Migration: https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app