Integrating Swift Package Manager With React Native Libraries

Authors
No items found.

React Native uses CocoaPods for iOS dependency management, but Swift Package Manager (SPM) has been gaining popularity as Apple's official solution. SPM is Apple's first-party dependency manager with native Xcode integration, while CocoaPods is a third-party tool that is expected to become read-only and gradually phased out.

Since React Native 0.75, there's been a solution to integrate SPM packages into React Native applications through the spm_dependency helper. This allows you to add SPM dependencies to your libraries, making it possible to use modern iOS libraries that are distributed exclusively through SPM.

Using SPM packages inside React Native app currently forces the entire iOS project to adopt use_frameworks! :linkage => :dynamic. This can be a drawback for teams that rely on static linking or have performance or binary size sensitivities.

In this article, we'll take a look at how you can use SPM packages in React Native for both remote and local packages.

Using remote SPM dependencies

React Native 0.75 introduced the spm_dependency helper method, available in the library podspec. This allows you to declare SPM dependencies alongside your existing CocoaPods configuration:

Pod::Spec.new do |s|
  s.name = "MyReactNativeLibrary"
  # ... other configuration
  
  spm_dependency(s,
    url: 'https://github.com/apple/swift-atomics.git',
    requirement: {kind: 'upToNextMajorVersion', minimumVersion: '1.1.0'},
    products: ['Atomics']
  )
end

This integration enables React Native libraries to consume modern Swift packages that are distributed exclusively through SPM, bridging the gap between the CocoaPods and SPM ecosystems.

Local SPM packages in monorepos

The original spm_dependency helper only worked with remote package URLs. For monorepo setups with local Swift packages, you needed an enhancement:

packages/
├── mobile-app/           # React Native app
├── shared-ui-kit/        # React Native library
└── core-utilities/       # Local Swift SPM package

Referencing core-utilities from shared-ui-kit wasn't possible because the implementation assumed all packages would be fetched from remote Git repositories.

Supporting local SPM packages

We shipped a fix that extends the spm_dependency helper to support local package references alongside remote ones.

This fix is currently in the main branch but not yet released. It will most likely ship in React Native 0.84, since the 0.83 branch was cut before it landed. To use local SPM packages today, you'll need to patch it in your node_modules before running pod install. This workaround will no longer be needed once the fix is included in an official React Native release. You can download a ready-to-apply patch from this gist.

Usage in monorepos

With local SPM package support, you can reference Swift packages within your monorepo:

Pod::Spec.new do |s|
  s.name = "SharedUIKit"
  # ... other configuration
  
  # Reference local SPM package
  spm_dependency(s,
    url: File.join(__dir__, '../core-utilities'),
    requirement: {},
    products: ['NetworkingUtils', 'DataModels']
  )
end

Paths are resolved relative to the podspec file, enabling flexible monorepo structures where React Native libraries can consume local Swift packages.

Under the hood

The SPM integration leverages CocoaPods' Xcodeproj gem to modify Xcode project files. When processing spm_dependency declarations, the system creates different types of package reference objects:

def add_spm_to_target(project, target, url, requirement, products)
  if File.exist?(url)
    # Create local package reference
    package_ref = project.new(Xcodeproj::Project::Object::XCLocalSwiftPackageReference)
    package_ref.relative_path = url
  else
    # Create remote package reference
    package_ref = project.new(Xcodeproj::Project::Object::XCRemoteSwiftPackageReference)
    package_ref.repositoryURL = url
  end
  
  # Link products to target (same for both types)
  products.each do |product|
    package_product = project.new(Xcodeproj::Project::Object::XCSwiftPackageProductDependency)
    package_product.productName = product
    target.package_product_dependencies << package_product
  end
end

These Xcodeproj::Project::Object classes represent the actual objects stored in Xcode project files. The Xcodeproj gem provides Ruby abstractions for manipulating .xcodeproj files, which are essentially property list files with a specific structure that Xcode understands.

  • XCLocalSwiftPackageReference: Represents a local Swift package dependency within the project.
  • XCRemoteSwiftPackageReference: Represents a remote Git repository containing a Swift package.
  • XCSwiftPackageProductDependency: Links specific products from a package to build targets.
If you're using use_frameworks! in your Podfile with :linkage => :static, you may encounter linker errors when integrating SPM packages. Consider using use_frameworks! without explicit linkage (which defaults to dynamic) or use_frameworks! :linkage => :dynamic for better SPM compatibility.

Conclusion

While React Native continues to work on migrating to SPM, you can use SPM packages today with your libraries! The spm_dependency helper enables both remote and (soon) local package integration, making it possible to build modern React Native libraries that leverage the Swift ecosystem.

Table of contents
Building high-quality iOS apps with React Native?

We support teams in building high-quality, native-feeling iOS apps.

Let’s chat

//

//
Insights

Learn more about iOS

Here's everything we published recently on this topic.

//
iOS

We can help you move
it forward!

At Callstack, we work with companies big and small, pushing React Native everyday.

Release Process Optimization

Ship faster with optimized CI/CD pipelines, automated deployments, and scalable release workflows for React Native apps.

React Native Brownfield

Integrate React Native into existing native application and start sharing code across platforms immediately.

Mobile App Development

Launch on both Android and iOS with single codebase, keeping high-performance and platform-specific UX.

React Native Modules Development

We help teams extend React Native with native modules that meet demanding performance, integration, or device access needs.