Integrating Swift Package Manager With React Native Libraries

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.

Insights

Learn more about iOS

cover

Oct 23Live Stream

Building Real-Time Live Activities in Expo

Learn how to add real-time LiveActivity updates to your Expo app using Swift native modules. In this stream, we implemented Apple’s Live Activities with Evan Bacon’s library, explored ActivityKit, and discussed cross-platform development with Solito 5 and Expo UI.

cover

Sep 11Article

How to Use Liquid Glass in React Native

Learn how to bring Apple’s new Liquid Glass design material into your React Native apps. This guide covers design best practices, performance tips, and examples using LiquidGlassView and LiquidGlassContainerView.

cover

Feb 27Article

Exposing SwiftUI Views to React Native: An Integration Guide

Learn how to seamlessly integrate SwiftUI views in React Native and enhance your app’s iOS capabilities with SwiftUI superpowers.

cover

Jan 16Article

Solving Swift Modular Header Issues in React Native for Good

Learn how to resolve Swift modular header errors in React Native. Explore solutions like static frameworks and a custom CocoaPods plugin.

cover

Jun 3Article

Handling Multiple Native iOS Views in React Native

In this article Piotr Trocki, software developer at Callstack, explains how to handle multiple Native iOS views in React Native.

cover

Nov 16Article

React Native Meets iPhoneX

Check this practical guide on adapting your React Native application to the new iPhone X, specifically when using react-native-navigation.

cover

Mar 19Tutorial

The Hard Way vs. The React Native AI SDK Way: Stop Writing Custom Modules for Every Model

Learn how React Native AI uses a unified provider model to switch between cloud and on-device LLMs without rewriting application logic, enabling reliable AI experiences online and offline.

cover

Mar 12Tutorial

Build Smarter Apps: Tool Calling & AI Orchestration Explained

Learn how on-device models in React Native can call tools, interact with external APIs, and return structured outputs you can use directly in application logic.

cover

Mar 5Tutorial

MLC LLM + React Native: On-Device AI Without the Pain

Learn how to run third-party on-device LLMs in React Native using MLC LLM. Choose your models, run them efficiently across platforms, and keep a unified JavaScript API with React Native AI.

cover

Feb 24Tutorial

Intelligent Fallbacks with Apple Intelligence in React Native

Learn how to use Apple’s built-in Foundation Models in React Native apps, reduce memory usage, and enable fast, fully on-device AI with React Native AI Apple.

cover

Feb 10Tutorial

What Is the React Native AI SDK? A Complete Intro & Quickstart

Learn why on-device AI matters for React Native apps, how local LLMs behave offline, and what problems React Native AI is designed to solve from day one.

cover

Jan 29Tutorial

Implementing an Android TurboModule with Kotlin

Learn how to implement a React Native TurboModule on Android, from the TypeScript spec and Codegen to the Kotlin implementation and package registration.

cover

Jan 19Tutorial

Working with Different Threads in Swift TurboModules

Learn how JavaScript, native module, background, and main threads interact in React Native TurboModules, and how to use GCD queues to run async work safely in Swift.

cover

Jan 9Tutorial

How to Add Type-Safe Constants to Swift TurboModules

Learn how to expose typed, immutable constants from a Swift TurboModule using Codegen, and get full end-to-end type safety between native and JavaScript.

cover

Dec 30Tutorial

Adding Event Emitters to Your TurboModule in Swift

Learn how to emit native events from a Swift TurboModule and subscribe to them in JavaScript, including proper memory management and Codegen integration.

cover

Dec 22Tutorial

Writing Your First TurboModule in Swift

Learn how to build a fully working TurboModule in Swift, integrate it with Codegen, and bridge it through Objective‑C inside an Expo app.