Expo rewrites iOS native modules
- Expo's SDK team rewrote the iOS native modules to remove the Objective‑C++ interop layer and implement direct Swift/JSI bindings for faster native‑JS calls. - Tomasz Sapeta highlighted the rewrite as reducing overhead and improving performance for Expo apps running on Apple platforms. - Dropping the Obj‑C++ layer simplifies interop complexity and can reduce QA and maintenance surfaces for Apple‑focused app teams. (x.com)
Expo’s iOS native module layer just got a deep plumbing rewrite — the kind users won’t see, but developers and performance-sensitive apps probably will. The Expo team replaced the old Objective-C++ JSI interop layer inside `expo-modules-core` with a new Swift-first package called `ExpoModulesJSI`. That change landed in the repo this week through a Tomasz Sapeta PR, and Expo already labels it as a breaking iOS change for module authors. (github.com) ### What actually changed? Before this, Expo’s iOS module system still leaned on a set of Objective-C++ wrapper types — things like `EXJavaScriptRuntime`, `EXJavaScriptObject`, `ExpoModulesHostObject`, and `EXSharedObjectUtils`. Those wrappers sat between Swift module code and React Native’s JSI layer. The new version removes that middle layer and rewrites the core type system, definitions, `AppContext`, and worklets integration on top of `ExpoModulesJSI`, which is a dedicated Swift package for talking to JSI. (github.com) ### Why does Objective-C++ matter here? Because Swift can’t talk to C++ directly in the smooth, native-feeling way developers want. For years, Objective-C++ was the adapter — useful, but awkward. It meant extra wrapper code, extra type conversions, and more moving parts whenever Expo needed Swift code to interact with the JavaScript runtime. The new package is built to give Swift type-safe bindings to JSI, so Expo can keep the public iOS side more “just Swift” while still reaching Hermes and the React Native runtime underneath. (github.com) ### Is this the same as the old React Native bridge story? Not really. Expo’s modules API was already built on JSI rather than the old JSON message queue bridge, so this is not a “bridge to JSI” migration. The more precise way to think about it is this: Expo already used the modern highway, but part of the iOS on-ramp was still built out of older Objective-C++ machinery. Now the on-ramp is being rebuilt in Swift-first form. Expo’s docs already describe its modules API as a JSI-based system with performance characteristics similar to Turbo Modules. (docs.expo.dev) ### So does this make apps faster? Probably in the places where native-to-JS and JS-to-native interaction overhead matters most — but Expo has not published a benchmark here yet. What the repo does make clear is the intent: fewer wrapper layers, a rewritten core, and direct Swift-facing JSI bindings. That usually means less glue code, fewer conversions, and a smaller maintenance surface. The performance claim is partly inference, but it is a well-grounded one from the architecture change itself. (github.com) ### Who feels this change first? Third-party native module authors on iOS. Expo marks the change as breaking and says modules depending on the old Objective-C++ JSI types will need to migrate to the new Swift-first API. So if a team built custom Expo modules that reached into those internal iOS runtime objects, this is not invisible cleanup — it is migration work. Regular Expo app developers may never notice directly unless an upstream library needs updating. (github.com) ### Why now? Because Expo has been pushing its modules API as the default native extension path for developers who want Swift and Kotlin ergonomics without dropping down into more C++-heavy Turbo Module internals. A Swift-first JSI layer fits that strategy better than keeping Objective-C++ as a permanent translation zone in the middle. It also lines up with Expo continuing to modernize its Apple stack — the same unpublished changelog section also bumps minimum iOS and tvOS to 16.4 and macOS to 13.4. (docs.expo.dev) ### What’s the real significance? Basically, Expo is trying to make its iOS native module system look more like the language developers actually write in. That matters for speed, but also for code health. Less interop code usually means fewer weird edge cases, easier debugging, and less QA around “did this wrapper layer translate the runtime object correctly?” It is the sort of rewrite that makes the platform feel simpler a year from now, not flashier today. (github.com) ### Bottom line This is an infrastructure story, not a feature launch. But it is a meaningful one. Expo just pulled a chunk of Objective-C++ out of the center of its iOS module runtime and replaced it with a Swift-first JSI package. For Apple-platform module authors, that is a real architectural shift — and probably a preview of how Expo wants native extensibility to work from here on out. (github.com)