◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/App Dev
◇ App Dev/2026-10-22Intermediate

Expo SDK 58 With Stripe: pod install Stops, and Whether to Turn Off Precompiled Modules or Wait

useFrameworks is already dynamic, yet pod install says Stripe is static and the SDK 58 iOS build stops. The reported conditions, three ways out, and a small script to check your own project first.

Expo225SDK 58Stripe20CocoaPods4iOS buildexpo-build-propertiesEAS Build23Rork595

I was going through my payment-related dependencies before moving to SDK 58 when one report in the Expo issue list made me stop scrolling. Stripe was in its title.

useFrameworks was already dynamic, and still pod install said Stripe was being built as a static library. When the setting you need is already there and the build still fails, you tend to look in the wrong place for a long time.

I haven't reproduced this setup myself. What follows comes from reading the issue and the comment where the Expo side reproduced it on EAS. On top of that, I wrote down a way to check whether your own project meets the conditions before you start a build.

The short version first. If you have Stripe, useFrameworks: "dynamic", and precompiled modules enabled, you are affected. There are three ways out, and the choice depends on how soon you need to ship and how much extra iOS build time you can live with.

What is happening

The report is expo/expo issue 51652. Here are the conditions.

ItemReported value
Expo58.0.11
React Native0.88.0
@stripe/stripe-react-native0.81.0
expo-modules-autolinking58.0.13
CocoaPods1.17.0
expo-build-properties (ios)useFrameworks: dynamic, usePrecompiledModules: true

Running npx expo prebuild --platform ios --clean makes CocoaPods stop with an error along these lines.

[!] [stripe-react-native] Resolving the Stripe iOS SDK through Swift Package
Manager requires dynamic frameworks, but stripe-react-native is building as
a static library. To fix, add `use_frameworks! :linkage => :dynamic` to your Podfile

There is a trap in reading this. The message tells you to add dynamic linkage, but that setting is already in place. What is missing is not a setting. Something else overrides the result.

The reporter traced it in Ruby. precompiled_modules.rb in expo-modules-autolinking collects pods that depend on React-Core into pods_to_downgrade and swaps their build type to a static library. Stripe's Swift Package Manager integration requires dynamic, and the two collide.

The Expo side's comment reached the same reading. They ran three builds of one project on the EAS iOS preview profile.

Stripe 0.81.0usePrecompiledModulesResult
yestrueFailed (Install pods)
yesfalseSucceeded
notrueSucceeded

So the build fails only when Stripe and precompiled modules are both present. Either one alone passes. Also, the EAS screen reportedly shows only "Unknown error. See logs of the Install pods build phase". You have to open the log of that phase to see the real message.

Check your own project before building

I wrote a small script that reads app.json and package.json and judges only whether the three conditions line up. Since the documentation lists usePrecompiledModules as true by default, a missing value is counted as enabled.

// check-stripe-linkage.js — check the Stripe + precompiled modules combination before building
// Usage: node check-stripe-linkage.js [project path]
const fs = require('fs');
const path = require('path');
 
const root = path.resolve(process.argv[2] || '.');
const readJson = (name) => {
  const p = path.join(root, name);
  return fs.existsSync(p) ? JSON.parse(fs.readFileSync(p, 'utf8')) : null;
};
 
const pkg = readJson('package.json');
if (!pkg) { console.error('package.json not found: ' + root); process.exit(2); }
 
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
const stripeVer = deps['@stripe/stripe-react-native'];
const expoVer = deps['expo'];
 
// app.json comes in two shapes: { "expo": {...} } and the bare object
const app = readJson('app.json');
const cfg = app ? (app.expo || app) : null;
if (!cfg) {
  const dyn = ['app.config.js', 'app.config.ts'].find((f) => fs.existsSync(path.join(root, f)));
  console.log(dyn
    ? `⚠️ ${dyn} has to be executed to read it. Check the expo-build-properties plugin by eye`
    : '⚠️ app.json not found');
  process.exit(dyn ? 0 : 2);
}
 
// Find expo-build-properties in plugins (a bare string entry means no options)
let ios = {};
for (const pl of cfg.plugins || []) {
  if (Array.isArray(pl) && pl[0] === 'expo-build-properties') ios = (pl[1] && pl[1].ios) || {};
}
const useFrameworks = ios.useFrameworks || '(not set)';
// Per the docs, usePrecompiledModules defaults to true
const precompiled = ios.usePrecompiledModules === undefined ? true : ios.usePrecompiledModules;
 
console.log(`expo                       : ${expoVer || '(none)'}`);
console.log(`@stripe/stripe-react-native: ${stripeVer || '(none)'}`);
console.log(`ios.useFrameworks          : ${useFrameworks}`);
console.log(`ios.usePrecompiledModules  : ${precompiled}${ios.usePrecompiledModules === undefined ? ' (default)' : ''}`);
 
if (!stripeVer) { console.log('✅ Stripe is not installed, so this issue does not apply'); process.exit(0); }
if (useFrameworks === 'dynamic' && precompiled !== false) {
  console.log('❌ Stripe + useFrameworks: dynamic + precompiled modules on. This combination stops prebuild / pod install on SDK 58');
  console.log('   → set ios.usePrecompiledModules to false, or test a build without Stripe');
  process.exit(1);
}
console.log('✅ This combination does not meet the reported failure conditions');

On my machine, a config with Stripe, dynamic, and no usePrecompiledModules stops with exit code 1. Setting usePrecompiledModules to false passes, and so does a setup without Stripe. What I confirmed is how this check behaves. I did not run a real pod install.

I made it return an exit code so you can put it in your package.json scripts or CI as a check before sending a build to EAS.

Three ways out

1. Turn precompiled modules off

This is the one that actually passed for both the reporter and the Expo side.

{
  "expo": {
    "plugins": [
      [
        "expo-build-properties",
        {
          "ios": {
            "useFrameworks": "dynamic",
            "usePrecompiledModules": false
          }
        }
      ]
    ]
  }
}

The cost can be read from the documentation. usePrecompiledModules switches between using prebuilt XCFrameworks and building from source. Turn it off and Expo's modules go back to building from source, so the iOS build should get heavier. I haven't measured by how much.

2. Handle it on Stripe's side

According to the Expo comment, Stripe has a way to set $StripeDisableSPM = true in the Podfile. The same comment adds that Stripe marks this as deprecated, that a managed project needs a config plugin to inject it into the Podfile, and that the Expo side didn't try it either.

I wouldn't pick this. It spends pre-release time on a road nobody has tested.

3. Wait

As of October 22 the issue is still open. The Expo side lists, as a design decision, either making precompiled modules support pods that must be dynamic, or keeping them static and printing a diagnostic. A fix on Stripe's side is mentioned as a possibility too. In other words, there is no outlook for when it gets fixed.

You can also keep shipping on SDK 57 and hold the move to 58. If this issue is your only reason to hold, watch how it moves and decide as you go.

Choosing

My line comes from two questions.

  • Do you need to ship iOS this month? If yes, choose 1. Removing Stripe would stop your payments, so that's not realistic.
  • Do you not need to ship this month, and have no particular reason to be on 58? Then choose 3.

For an indie developer who has added payments, a slightly heavier build costs far less than not being able to submit. Build time can be measured and trimmed later. A release window doesn't come back.

Pay for the slowness you can fix, never for the delay you can't get back. I try to keep this line even on SDK updates.

After you turn it off

Once usePrecompiledModules is false, run npx expo prebuild --platform ios --clean once and confirm pod install goes through to the end. If you build on EAS and it fails, open the log of the Install pods phase.

Two other SDK 58 checks are worth running before an upgrade: the .env.staging file that is no longer read and the permission strings that pile up in Info.plist. For wiring in Stripe itself, see Rork × Stripe subscription implementation.

Start by running check-stripe-linkage.js once and see whether your own project is affected.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

◇ App Dev2026-09-18
The three lines I check when prebuild stops on the standard SDK 57 Swift AppDelegate error
Turning on ios.enableSceneSupport for iOS 27 can stop prebuild cold. The cause was not my SDK version but the shape of AppDelegate.swift. Here are the three lines to check, and why copying the SDK 58 migration steps by hand will break your build.
◇ App Dev2026-10-15
When Only EAS Build Fails with "No matching variant", Check Your Local android/build First
Gradle passes on your machine, but the Android build on EAS stops at "No matching variant of project". Reading the reports on GitHub, I traced how a Windows-generated autolinking cache can reach the Linux builder, and wrote a small script that checks for it before you queue a build.
◇ App Dev2026-10-14
App Review Says "Guideline 2.1, Blank Screen": Three Places to Look in an Expo Release Build
It opens fine in TestFlight, yet review rejects it for a blank screen. Here is the order I check things in an Expo + EAS release build: which environment holds your variables, secret visibility during config resolution, and what the reviewer's device does differently.