Upgrading to Expo SDK 55: breaking changes, pnpm catalog, and the official Claude plugin

Storyie Engineering Team
7 min read

How we upgraded Storyie from Expo SDK 54 to 55 — covering the three breaking changes that hit us (newArchEnabled removal, splash config migration, and mandatory edge-to-edge), how pnpm catalog made version management painless, and how Expo's official upgrading-expo Claude plugin handled most of the mechanical work.

Upgrading to Expo SDK 55: breaking changes, pnpm catalog, and the official Claude plugin

SDK 55 is a meaningful update: React 19.2, React Native 0.83.2, and the New Architecture promoted from opt-in to the only architecture. We upgraded the Storyie monorepo from SDK 54 to 55 and came away with a few lessons worth sharing — both about the breaking changes themselves and about how we used Expo's official upgrading-expo Claude plugin to handle most of the mechanical work.

TL;DR

What changed

Impact

Action

newArchEnabled removed

New Architecture is now mandatory and the only option

Delete the flag from app.config.ts; audit native module compatibility

splash config deprecated

Top-level splash key replaced by expo-splash-screen plugin config

Move splash settings into the plugins array

StatusBar backgroundColor dropped

Android edge-to-edge is now mandatory

Remove the prop; rely on SafeAreaView and inset handling instead

React 19.1 → 19.2, RN 0.81 → 0.83

Minor React changes; significant RN internal changes

Check native dependency compatibility

  • pnpm catalog keeps all SDK-related version bumps in one file — the upgrade was a single diff in pnpm-workspace.yaml plus a pnpm install.
  • The upgrading-expo Claude plugin detected and handled the three config changes automatically.
  • Project-specific skills (.claude/skills/) filled in what the plugin couldn't know — our actual dependency versions, monorepo layout, and custom config.

The three breaking changes that required real work

1. newArchEnabled removal

SDK 55 drops the New Architecture opt-in entirely. If app.config.ts still carries newArchEnabled: true, you need to remove it:

// app.config.ts
- newArchEnabled: true,
+ // newArchEnabled option was removed in SDK 55

The code change is trivial. The implication is not: there is no bridge fallback in SDK 55. Any native module that wasn't fully New Architecture-compatible breaks at runtime. We had already validated our dependency surface when we initially enabled the New Architecture, so nothing broke. Projects that skipped that validation step should audit native modules before upgrading.

Also worth checking: CI scripts, environment variables, and build configs that reference newArchEnabled — even as a comment or a conditional — should be cleaned up to avoid confusion.

2. splash config migration

The top-level splash field in app.config.ts is gone in SDK 55. Configuration moves into the expo-splash-screen plugin entry in the plugins array. For reference, the field we removed looked like this:

// app.config.ts
- splash: {
-   image: "./assets/images/splash_2732.png",
-   resizeMode: "contain",
-   backgroundColor: "#F5F0EC",
-   dark: {
-     image: "./assets/images/splash_2732-dark.png",
-     backgroundColor: "#2A2520",
-   },
- },

Storyie supports dark mode splash screens, which made this slightly more involved — the plugin's option shape for per-scheme images and colors is different from the old dark: nesting. The upgrading-expo plugin knew the correct target shape and produced the right plugin configuration without us having to manually dig through the expo-splash-screen changelog.

3. Android edge-to-edge and StatusBar.backgroundColor

SDK 55 makes edge-to-edge layout mandatory on Android. Your app's content now extends behind the system status bar and navigation bar. As a consequence, the backgroundColor prop on StatusBar has no effect and logs a warning.

This is not just a config tweak — it's a layout design concern. If your screens relied on StatusBar.backgroundColor to create a visually distinct header area, you need to rethink that with proper SafeAreaView padding and inset-aware layout. For us, it meant auditing header components and checking that bottom-tab navigation accounted for the navigation bar inset. The long-term result is a more native-looking UI; the short-term cost is a focused layout pass.

4. React and React Native version bumps

React 19.2 is a minor change — the upgrade was invisible at the React API level. React Native 0.83, however, carries significant internal changes that affect native module interop. The most reliable way to validate this is to build and run on actual devices (not just simulators) after upgrading. Simulators can mask issues that surface on hardware, particularly around New Architecture JSI behavior.

pnpm catalog: why version management was a non-issue

Storyie uses pnpm workspace's catalog feature to centralize dependency versions. All SDK-related packages are declared once in pnpm-workspace.yaml:

# pnpm-workspace.yaml
catalog:
  expo: ^55.0.0
  expo-modules-core: ^55.0.0
  react: 19.2.0
  react-dom: 19.2.0
  react-native: 0.83.2

Each package.json that needs these packages references them as "expo": "catalog:" rather than specifying a version inline. When we upgraded, the entire version bump was a single edit to pnpm-workspace.yaml followed by pnpm install.

Without a catalog, the same bump would have required editing multiple package.json files across the monorepo — and missing one means a mixed-version state that produces mysterious build failures. If you are running a pnpm monorepo and haven't adopted catalogs yet, SDK upgrades are a good forcing function.

Semi-automating the upgrade with the upgrading-expo plugin

Expo publishes an official Claude Code plugin collection called expo-plugins. The upgrading-expo plugin in that collection gives Claude structured knowledge of SDK breaking changes and migration steps. You enable it in .claude/settings.json:

{
  "enabledPlugins": {
    "upgrading-expo@expo-plugins": true
  }
}

With the plugin active, we told Claude to upgrade to SDK 55 and handle the breaking changes. It:

  1. Detected newArchEnabled in app.config.ts and removed it — knowing this was a SDK 55 deprecation, not an accidental deletion.
  2. Migrated the splash config to the plugin format, including the dark mode configuration.
  3. Updated the catalog in pnpm-workspace.yaml rather than individual package.json files — the plugin understood our monorepo's dependency management approach.
  4. Checked compatibility for libraries we use (react-native-webview, etc.) against the SDK 55 / RN 0.83 matrix.

The plugin provides Expo common knowledge. What it doesn't know is project-specific: which SDK version we were on before the upgrade, what custom native modules we use, how our monorepo is structured. That context lives in our .claude/skills/ files:

.claude/skills/
├── expo-mobile/SKILL.md      # Current SDK version, EAS config, native modules
├── monorepo-architecture/    # pnpm workspace layout, catalog conventions
└── ...

After completing the upgrade, we updated the version references in expo-mobile/SKILL.md — so the next upgrade starts with accurate ground-truth rather than stale version numbers.

The combination that works: plugin (Expo's shared upgrade knowledge) + skills (your project's specific state). Neither is sufficient alone.

What we learned

Breaking changes in SDK upgrades are mostly deletions

Looking at SDK 55 as a whole: newArchEnabled removed, splash deprecated, backgroundColor dropped. The pattern across Expo upgrades we've done is that breaking changes tend to be about removing old config or deprecated APIs — you're "adding" very little, just cleaning up. This is actually good news for automation: determining what to remove is mechanical (compare the release notes against the current config), which is exactly what an AI tool with domain knowledge can do reliably.

Edge-to-edge needs design attention, not just a prop deletion

The StatusBar.backgroundColor removal is technically a one-line change, but it exposes a layout assumption that often runs deeper. Any screen that previously controlled status bar color as a design affordance needs to be rethought in terms of safe area insets and content extension. We found a few header components that needed an additional pass before the layout felt right. Budget time for this — it's not a five-minute fix if you have many screens.

Skipping SDK versions is possible but not recommended

We jumped 54 → 55, skipping the intermediate 54 release cycle. This worked for us because our native dependency surface is small (Lexical runs inside a "use dom" WebView, which isolates a lot of RN version sensitivity) and because CI caught issues quickly. For projects with deeper native dependencies, we'd recommend against it. The incremental path surfaces incompatibilities one version at a time, which is much easier to debug than finding a breakage and having to bisect two version jumps.

Takeaways

  • pnpm catalog reduces SDK version management to a single file edit. If your monorepo doesn't use catalogs, this upgrade is a good time to start.
  • upgrading-expo plugin handles the mechanical config changes reliably when given the right project context. Pair it with project-specific Claude skills for best results.
  • Breaking changes lean toward removalnewArchEnabled, splash, backgroundColor. Automation-friendly by nature.
  • Edge-to-edge on Android is a real design consideration, not just a prop swap. Audit your header and bottom navigation layouts before shipping.
  • Validate on real devices after any major RN version bump — simulators mask issues that surface on hardware.

Related Posts

Try Storyie

Storyie runs the same codebase on the web at storyie.com and on the iOS app. The SDK 55 upgrade was invisible to users — which is exactly how it should be.