In React Native 0.87, what does it take to keep an app on JavaScriptCore instead of Hermes, and why do most teams stop doing so?
answer
- JSC left core in 0.81
- @react-native-community/javascriptcore
- useThirdPartyJSC and USE_THIRD_PARTY_JSC
- USE_HERMES=0 alone stops pod install
- no bytecode, separate release train
basics
~20 sJavaScriptCore is no longer in core since 0.81: an app must add @react-native-community/javascriptcore and select it in the build. Most teams move to Hermes V1 instead, which core ships, tests and precompiles to bytecode for faster startup.
solid answer
~40 sReact Native removed its built-in JavaScriptCore (JSC) in **0.81**, after moving it to the community package `@react-native-community/javascriptcore` in 0.79. On 0.87 an app that wants JSC installs that package, follows its instructions, and selects it in the build: React Native's Android Gradle plugin reads a `useThirdPartyJSC` property, and the iOS pods script reads `USE_THIRD_PARTY_JSC=1`. Old switches no longer work: `USE_HERMES=0` without the third-party flag makes `pod install` print an error and stop, the Podfile's `hermes_enabled` argument is deprecated, and `hermesEnabled=false` alone on Android only earns a warning. Teams usually migrate instead because JSC ships source rather than build-time bytecode, follows its own release schedule, and sits outside the engine React Native builds and tests every release, which since 0.84 is **Hermes V1**, with its opt-out gone by 0.87.
code
bash · 5 lines# iOS: selects the community JavaScriptCore instead of Hermes at pod install
USE_THIRD_PARTY_JSC=1 bundle exec pod install
# Rejected in 0.87: prints that JSC moved to community support and exits
USE_HERMES=0 bundle exec pod installgo deeper
Know that Hermes is the default engine and that JavaScriptCore is no longer part of React Native itself since 0.81; it lives in a community package.
Explain what selecting JSC now takes on each platform and why the old switches, USE_HERMES=0 and hermesEnabled=false, no longer do it.
Lead an engine migration: find what truly depends on JSC, validate on Hermes V1 in release builds, and account for the removed Hermes V1 opt-out when planning the upgrade.
Weigh the ongoing cost of an engine outside core's release train against the migration work, and decide whether a JSC dependency justifies owning that divergence.
## How the engine choice changed For years React Native offered two engines: **JavaScriptCore (JSC)**, the engine behind Safari, and **Hermes**, built for React Native. Hermes became the default in 0.70, and the project then reduced core's surface: 1. **0.79**: JSC starts moving to a community-maintained package, `@react-native-community/javascriptcore`, released on its own schedule. Core's copy remains for now. 2. **0.80**: the last release with first-party JSC support. 3. **0.81**: the built-in JSC is removed. Any app that needs JSC must use the community package to upgrade. 4. **0.82**: Hermes V1 appears as an experimental opt-in. 5. **0.84**: Hermes V1 becomes the default on iOS and Android. Opting back to the legacy Hermes required building React Native from source. 6. **By 0.87**: that opt-out is gone. The Gradle plugin warns that opting out of Hermes V1 is no longer supported and ignores `hermesV1Enabled=false`, and the iOS pods script sets `RCT_HERMES_V1_ENABLED=1` unconditionally. ## What staying on JSC requires in 0.87 The community package's own README is the installation authority. What React Native's build reads is: - **Android**: the Gradle plugin checks a `useThirdPartyJSC` property. With it set and Hermes disabled, the packaging keeps `libjsc.so` and drops the Hermes libraries. - **iOS**: the pods script checks the `USE_THIRD_PARTY_JSC=1` environment variable at `pod install`. When set, pods depend on the JSC integration instead of `hermes-engine`; otherwise Hermes is always chosen. The switches older guides mention now behave like this: | Old switch | Behaviour in 0.87 | |---|---| | iOS `USE_HERMES=0` without `USE_THIRD_PARTY_JSC=1` | `pod install` prints that JSC moved to community support and exits | | Podfile `hermes_enabled:` argument | Deprecated; the engine is decided by `USE_THIRD_PARTY_JSC` | | Android `hermesEnabled=false` alone | Gradle prints a "JavaScriptCore is being moved" warning pointing at the community package | | Android `hermesV1Enabled=false` | Ignored with a warning; Hermes V1 is always used | ## Why most teams move to Hermes instead - **Startup**: Hermes release builds ship bytecode compiled by `hermesc`, so the device skips parsing and compiling the bundle. A JSC build ships JavaScript source that is parsed on every cold start. - **Memory and size**: React Native's docs report lower memory use and smaller apps with Hermes for many apps, and Hermes V1 added further speed and memory gains. - **One engine, one train**: every React Native release pins and tests a matching Hermes. The community JSC follows its own schedule, so each upgrade adds a compatibility question. - **Shrinking surface**: core has already removed its JSC copy and the Babel transforms that existed for non-Hermes engines, so the direction of travel is clear. ## When a team might still choose JSC The community package exists because some apps depend on engine-specific behaviour, or have a dependency not yet validated on Hermes. The honest process is: 1. **List what actually depends on JSC**: a library, a behaviour difference, a test result. 2. **Try the app on Hermes V1 in a release build** and run the full test suite and a manual pass on real devices. 3. **Fix or replace the blocking pieces** where possible. 4. **If JSC remains**, budget for tracking the community package's releases alongside every React Native upgrade. ## What changes for an Expo project Expo SDK 57 apps run React Native 0.86, which is already past both milestones: core contains no JavaScriptCore, and Hermes V1 is the default engine. The engine facts above therefore apply to Expo-managed and bare projects alike; what differs is only where the native build settings live. ## Reading an upgrade failure correctly - A `pod install` that stops with a message about JSC moving to community support is not a CocoaPods problem: an old `USE_HERMES=0` is still set somewhere, often in a CI script. - A Gradle warning titled "JavaScriptCore is being moved" means `hermesEnabled=false` is set without the third-party JSC setup. - A warning about `hermesV1Enabled` means that line no longer does anything: the app runs on Hermes V1 regardless, so remove it and test on V1. ## Summary In React Native 0.87, JSC is an opt-in community engine selected with `useThirdPartyJSC` on Android and `USE_THIRD_PARTY_JSC=1` on iOS, while Hermes V1 is the engine core ships and no longer lets you switch off. Most teams take the startup, memory and maintenance advantages and drop JSC.
- Can a React Native 0.87 app stay on the pre-V1 Hermes to avoid behaviour changes?No. In 0.84, the release that made Hermes V1 the default, opting out required overriding `hermes-compiler` and building React Native from source. By 0.87.1 the Android Gradle plugin logs that opting out of Hermes V1 is no longer supported and ignores `hermesV1Enabled=false`, and the iOS pods script forces `RCT_HERMES_V1_ENABLED=1`. Regressions have to be fixed or reported, not avoided.
- What is the first thing to check when an upgrade to 0.81 or later fails on an app that used JSC?Whether the app still relies on core's JSC through the old switches: `USE_HERMES=0` for pods or `hermesEnabled=false` for Gradle. Core no longer contains JSC, so the fix is either adding `@react-native-community/javascriptcore` with `USE_THIRD_PARTY_JSC=1` or `useThirdPartyJSC`, or moving the app to Hermes.
saying these in an interview costs you the question
- Setting hermesEnabled=false is enough to switch a 0.87 app to JavaScriptCore
- The Podfile's hermes_enabled: false argument selects JSC on iOS
- hermesV1Enabled=false keeps a 0.87 app on the legacy Hermes
- JSC and Hermes both precompile the bundle to bytecode at build time
- The community JSC package is released in lockstep with React Native