Hermes vs JSC in 2026: What Actually Changed for React Native Startup and Memory
Hermes has been the default in React Native for a while, but the JSC-vs-Hermes decision still shows up in real projects. Here's what's changed, what still bites, and when we'd still reach for JSC.
Hermes has been the default JavaScript engine in React Native for long enough that most teams stopped thinking about the choice. But every few months a client asks us why their app feels slow on a mid-range Android, or why their crash reports are unreadable, and the answer traces back to engine decisions made at project setup. In 2026 the Hermes-vs-JSC question is narrower than it used to be — but it's not gone.
Where the engines stand in 2026
Hermes is an ahead-of-time bytecode engine built specifically for React Native. It ships as the default in every new RN template and has been the recommended path since the New Architecture became stable. JSC (JavaScriptCore) is Apple's engine on iOS and, on Android, a bundled build maintained by the React Native community.
The practical state of play:
- Hermes ships with full New Architecture support, source-map-backed stack traces, Chrome-compatible debugging via the Hermes debugger, and precompiled bytecode bundles.
- JSC on iOS is still the system engine — you can't remove it — but you can choose to run your JS on it instead of Hermes.
- JSC on Android is maintained but no longer the default. Some libraries have quietly stopped testing against it.
So the question isn't "which engine is better" in the abstract. It's whether your specific app benefits from switching one of them off.
Startup time: the number everyone quotes
Hermes wins cold start on Android, and it's not close. Because the JS bundle is precompiled to bytecode at build time, there's no parse step at launch. On low-end Android devices — the ones your analytics dashboard is quietly hiding from you — this is the difference between a two-second TTI and a five-second one.
In our experience:
- On Android mid-tier devices (something in the Snapdragon 6-series range), Hermes shaves roughly 30–50% off time-to-interactive versus JSC.
- On modern iPhones the gap is much smaller — often within 100–200ms — because JSC on iOS is heavily optimized by Apple and the parse cost is less painful.
- On older iPhones still in circulation (SE 2nd gen, older iPads), Hermes still helps, just less dramatically.
If your app targets emerging markets or you care about the first-launch experience for users on cheap hardware, this alone settles it.
The bytecode caveat
Hermes bytecode is architecture-dependent-ish and version-locked to the engine that shipped with your RN version. That matters for two things: OTA updates and CodePush/EAS Update flows. You cannot ship a Hermes bytecode bundle built against RN 0.77 to a binary running RN 0.76. This isn't new, but we still see teams get burned when they upgrade RN in the store binary and forget to invalidate their OTA channel.
// app.config.js — pinning the runtime version to the native app version
// prevents shipping incompatible Hermes bytecode over the air
export default {
expo: {
runtimeVersion: { policy: 'nativeVersion' },
updates: {
url: 'https://u.expo.dev/your-project-id',
},
},
};
Memory: the quieter win
Hermes was designed with a generational GC tuned for React Native workloads — lots of short-lived objects from render cycles, plus a long-lived component tree. On Android in particular, this shows up as:
- Lower steady-state RSS, often 20–30% less than JSC in our measurements.
- Fewer OOM kills on 3GB-RAM devices when the app backgrounds and returns.
- Smoother behavior when a large list re-renders repeatedly.
The iOS memory picture is muddier because iOS aggressively reclaims memory system-wide and the JSC-vs-Hermes delta gets absorbed into OS behavior. If you're chasing memory wins specifically to survive the iOS extension memory limits (share extensions capped around 120MB, notification service extensions tighter still), Hermes helps — but architectural choices matter more.
Bundle size and binary size
This one confuses people. Hermes precompiles your JS to bytecode, which is larger on disk than the equivalent minified JS. But the engine itself replaces JSC in your APK/IPA, and the net result on Android is usually a wash or a small win once you account for the fact that JSC-on-Android was a bundled dependency.
On iOS, enabling Hermes adds the Hermes engine to your binary — JSC is still there as the system engine, you just aren't using it. Expect a bump of a few MB in the IPA. For most apps this is a rounding error against image assets and native dependencies, but if you're fighting to stay under a cellular download threshold it's worth measuring.
Debugging and crash reports
This is where JSC used to have an advantage and no longer does. In 2026:
- Hermes source maps are stable and the RN CLI uploads them cleanly to Sentry, Bugsnag, and Crashlytics.
- The Hermes debugger integrates with modern Chrome DevTools and the React DevTools work end-to-end.
- Stack traces in production are readable if — and only if — you actually upload the source maps as part of your release pipeline.
The war story here: we've inherited more than one project where crash reports were unreadable garbage because the CI job that built the release binary wasn't uploading hermes-sourcemap artifacts. If you're on Hermes and your Sentry issues look like hermes:0:12345, you have a CI problem, not an engine problem.
# Sentry upload for Hermes source maps (Android release example)
npx sentry-cli sourcemaps upload \
--dist $BUILD_NUMBER \
--release $APP_VERSION \
android/app/build/generated/sourcemaps/react/release/index.android.bundle.map
When we'd still consider JSC
There are narrow cases where JSC is still the pragmatic pick:
- You depend on a native library that hasn't been updated for Hermes. This is rarer than it used to be, but legacy commerce SDKs and some region-specific payment providers still ship JSC-only quirks. Test early.
- You need
Intlbehavior that matches the platform exactly. Hermes ships its ownIntlimplementation. It's close to spec but not identical to what iOS Safari or Android Chrome do. If your app relies heavily on locale-specific number, date, or collation output — pricing displays, sorted catalogues — verify parity before you ship. - You're running an unusual JS workload. If your app does heavy synchronous number-crunching in JS (crypto, large JSON transforms, geometry), profile both. Hermes optimizes for typical RN workloads; JSC's JIT can be faster for tight numeric loops. This is rare in mobile apps but real when it happens.
- You're stuck on an old RN version with a known Hermes bug. Sometimes the fastest path to a release is flipping the engine flag, shipping, and doing the RN upgrade properly next sprint.
Note that on iOS you can only ship one engine per binary, so "use JSC for one screen" isn't a thing.
The New Architecture wrinkle
If you're on the New Architecture — Fabric renderer and TurboModules — Hermes is the well-trodden path. JSC works, but you'll spend more time on the edges: fewer people have hit the same bugs, and the RN team's testing matrix is Hermes-first. For a greenfield project in 2026, choosing JSC with the New Architecture is choosing to be a beta tester for a combination nobody else runs.
How to actually measure the difference
Don't take our word for it, or anyone else's. Build two release variants and measure on real hardware:
- TTI: from process start to first meaningful screen, measured with
Systraceon Android oros_signposton iOS. - Memory: steady-state RSS after five minutes of typical use, plus peak during a known-heavy flow.
- Bundle size: the actual delivered APK/IPA, not the JS bundle.
- Frame drops: JS thread frame time under a scripted scroll of your busiest list.
Run each measurement at least ten times per device and look at medians, not averages. Single-run numbers on mobile are noise.
Where we'd start
If you're greenfielding a React Native app today, use Hermes. Don't overthink it. Wire up source-map upload to your crash reporter on day one so you never ship a release without it, and pin your OTA runtimeVersion to the native version so Hermes bytecode mismatches can't reach production.
If you're on an older project still running JSC, don't switch engines mid-sprint. Do it as part of a planned RN upgrade, run both variants through your QA matrix for at least one release cycle, and pay special attention to Intl output and any native modules that touch the JS runtime directly. The upside — faster startup, lower memory, better tooling — is real. The downside is usually a handful of small fixes you'd rather discover in staging than in a store rollout. If you want a second pair of eyes on the migration, our mobile team has done this a few times.
Want a team like ours?
72Technologies builds production software for the kind of teams who actually read this blog.
Start a projectKeep reading
Deep Linking in React Native 2026: Universal Links, App Links, and the Edge Cases That Break Onboarding
Deep links look trivial until a marketing campaign melts down because iOS opens Safari instead of your app. Here's how we wire universal links, App Links, and Expo Router without the usual footguns.
Expo Dev Client vs Bare Workflow in 2026: When Managed Stops Being Enough
Expo's managed workflow got dramatically more capable in 2025, but there's still a line where dev client saves you and bare workflow becomes inevitable. Here's how we decide on real projects.
Background Tasks in React Native 2026: Why iOS Kills Your Sync and How to Work Around It
Background execution is where cross-platform apps quietly fall apart. Here's what actually works on iOS and Android in 2026, and where you should stop fighting the OS.
