Hermes Engine in React Native: Warum sie Apps schneller macht
AI generated
RN
native
React Native · Hermes · JSI · Mobile Performance
Die Hermes Engine in React Native
warum sie Apps spürbar schneller macht

Die Hermes Engine ist die JavaScript-Laufzeitumgebung, die React Native seit Version 0.70 standardmäßig verwendet, um Apps schneller zu starten und mit weniger Speicher auszukommen. Statt JavaScript bei jedem App-Start neu zu parsen, kompiliert Hermes den Code bereits beim Build in Bytecode vor, wovon besonders ältere Android-Geräte mit begrenztem Arbeitsspeicher profitieren.

14 Min. Lesezeit Hermes · JSI · Bytecode · Garbage Collection React Native 0.70+ · Expo · New Architecture

1. Warum React Native eine eigene JS-Engine braucht

Bis React Native 0.70 lief JavaScript standardmäßig in JavaScriptCore (JSC), der Engine hinter Safari. JSC ist auf Desktop- und iOS-Geräten ausgereift, war aber nie für die Startbedingungen typischer Android-Geräte optimiert: begrenzter Arbeitsspeicher, langsamere CPUs und ein App-Start, der jedes Mal komplettes JavaScript-Parsing erfordert. Meta entwickelte deshalb die Hermes Engine gezielt für mobile Endgeräte, mit einem klaren Ziel: schnellerer Start und geringerer Speicherverbrauch, ohne dass Entwickler ihren Code anpassen müssen.

Seit React Native 0.70 ist Hermes die Standard-Engine auf beiden Plattformen, iOS eingeschlossen. Das war ein bewusster Strategiewechsel: Statt eine universelle Engine für alle JavaScript-Umgebungen zu verwenden, bekommt React Native eine Laufzeit, die exakt auf die Einschränkungen mobiler Geräte zugeschnitten ist. Für Teams, die auf große Nutzerzahlen mit älteren Android-Geräten in Schwellenmärkten setzen, ist das kein Detail, sondern ein entscheidender Faktor für Conversion und App-Store-Bewertungen.

Der Kern des Unterschieds liegt nicht in der Sprache selbst, sondern darin, wie und wann JavaScript in Bytecode überführt wird. Genau dieser Mechanismus ist das Thema der folgenden Abschnitte: von der Kompilierung über den App-Start und die Garbage Collection bis zur praktischen Einrichtung und den Grenzen der Hermes Engine.

2. AOT-Bytecode-Kompilierung: das Herzstück von Hermes

Der zentrale Unterschied der Hermes Engine zu klassischen JS-Engines ist Ahead-of-Time-Kompilierung (AOT). Statt JavaScript-Quellcode zur Laufzeit zu parsen und per Just-in-Time-Compiler (JIT) in Maschinencode zu übersetzen, kompiliert Hermes den JavaScript-Code bereits während des Build-Prozesses mit dem Tool hermesc in ein kompaktes Bytecode-Format. Die App enthält beim Ausliefern also keinen JS-Quelltext mehr, sondern direkt ausführbaren Bytecode.

Dieser Ansatz verschiebt teure Arbeit vom Gerät des Nutzers auf die Build-Pipeline des Entwicklers. Parsing, Syntaxanalyse und ein Großteil der Optimierungsentscheidungen passieren einmalig beim Build, nicht bei jedem einzelnen App-Start auf potenziell tausenden unterschiedlichen Geräten. Für eine Engine, die Millionen von App-Starts über sehr heterogene Hardware hinweg bedienen muss, ist das ein fundamentaler Effizienzgewinn gegenüber klassischem JIT-Verhalten.

Die Metro-Bundler-Integration macht diesen Schritt für Entwickler unsichtbar: Beim Produktions-Build wird der JavaScript-Bundle automatisch durch hermesc geschickt und als .hbc-Bytecode-Datei in die App eingebettet. Entwickler schreiben weiterhin normales JavaScript oder TypeScript, die Umwandlung in Bytecode ist ein Build-Artefakt, das erst beim Release-Build sichtbar wird.


# Hermes bytecode compiler runs automatically during release builds
# Manual invocation for inspection purposes:
node_modules/react-native/sdks/hermesc/osx-bin/hermesc \
  --emit-binary \
  -O \
  -out index.android.bundle.hbc \
  index.android.bundle

# Inspect bytecode size vs raw JS bundle size
ls -lh index.android.bundle index.android.bundle.hbc

3. App-Start in der Praxis: Parse-Kosten gegen Bytecode laden

Um zu verstehen, warum die Hermes Engine den App-Start beschleunigt, hilft ein Blick auf die klassische JSC-Startsequenz: Die Engine lädt den JS-Bundle als Text, tokenisiert ihn, baut einen Syntaxbaum auf, führt semantische Prüfungen durch und beginnt erst dann mit der Ausführung. Bei größeren Bundles, wie sie in produktiven React-Native-Apps mit vielen Bildschirmen und Bibliotheken üblich sind, macht dieser Parse-Schritt einen spürbaren Anteil der gesamten Time-to-Interactive (TTI) aus.

Hermes überspringt diesen Schritt fast vollständig. Da der Bytecode bereits vorliegt, muss die Engine ihn beim Start nur noch laden und interpretieren, ohne vorher Text in eine Zwischenrepräsentation umzuwandeln. Das Ergebnis ist eine deutlich kürzere Zeitspanne zwischen App-Icon-Tap und interaktivem ersten Bildschirm, insbesondere auf Geräten mit langsameren CPUs, bei denen das Parsing anteilig am stärksten ins Gewicht fällt.

Dieser Effekt ist nicht gleichmäßig über alle Geräteklassen verteilt: Auf leistungsstarken, aktuellen iPhones ist der Unterschied oft kaum wahrnehmbar, weil moderne JSC-JIT-Compiler dort sehr schnell parsen. Auf preisgünstigen Android-Geräten mit wenig RAM und schwacher CPU, wie sie in vielen Wachstumsmärkten dominieren, macht sich die Hermes Engine hingegen am deutlichsten bemerkbar, oft mit spürbar kürzeren Ladezeiten bei App-Kaltstarts.

4. Speicherverbrauch und Garbage Collection

Neben dem Start ist der Speicherverbrauch der zweite große Vorteil der Hermes Engine. Hermes verwendet einen generationellen Garbage Collector, der Objekte nach ihrer erwarteten Lebensdauer in verschiedene Speicherbereiche (Generationen) einteilt. Kurzlebige Objekte, wie sie bei jedem Rendern einer React-Komponente entstehen, werden in einem kleinen, schnell durchsuchbaren jungen Speicherbereich verwaltet und effizient wieder freigegeben, ohne den gesamten Heap durchsuchen zu müssen.

Dieses Design reduziert zwei konkrete Probleme im mobilen Kontext: Out-of-Memory-Abstürze auf Geräten mit wenig RAM und GC-bedingte Ruckler, die als sichtbares Stottern in der Benutzeroberfläche wahrgenommen werden. Da mobile Betriebssysteme Apps bei Speicherdruck aggressiv beenden, ist ein kleinerer, effizient verwalteter Heap direkt mit besserer App-Stabilität verknüpft, nicht nur mit abstrakter Performance.

In der Praxis zeigt sich das besonders bei Listen-lastigen Bildschirmen mit vielen wiederverwendeten Zellen, etwa in Social-Feeds oder Produktkatalogen. Ohne effiziente Garbage Collection sammeln sich beim schnellen Scrollen viele kurzlebige Zwischenobjekte an, deren Aufräumen bei einer weniger mobil-optimierten Engine zu sichtbaren Frame-Drops führen kann. Die generationelle Strategie von Hermes hält genau diese Muster performant.

5. Hermes aktivieren und verifizieren

Da die Hermes Engine seit React Native 0.70 Standard ist, müssen die meisten neuen Projekte nichts weiter konfigurieren. In älteren Projekten oder bei manueller Kontrolle lässt sich die Engine explizit über gradle.properties für Android und die Podfile für iOS steuern. In Expo-Projekten genügt ein Eintrag im app.json, um die Engine pro Plattform festzulegen.

Wichtig ist die Verifikation nach jedem Build: Ein einfacher Check über das globale HermesInternal-Objekt zeigt zur Laufzeit zuverlässig, ob die App tatsächlich mit Hermes läuft oder unbemerkt auf die klassische Engine zurückgefallen ist, etwa nach einer fehlerhaften Konfigurationsänderung.


{
  "expo": {
    "name": "MyApp",
    "jsEngine": "hermes",
    "android": {
      "jsEngine": "hermes"
    },
    "ios": {
      "jsEngine": "hermes"
    }
  }
}

// Verify Hermes is actually active at runtime
import { useEffect } from 'react';

function EngineCheck() {
  useEffect(() => {
    // global.HermesInternal only exists when Hermes is the active engine
    const isHermes = () => !!global.HermesInternal;
    console.log('Running on Hermes:', isHermes());
  }, []);

  return null;
}

export default EngineCheck;

Auf der nativen Seite lohnt sich ein Blick in android/gradle.properties (hermesEnabled=true) und die iOS-Podfile (:hermes_enabled => true), falls ein Projekt aus einer älteren React-Native-Version migriert wurde. Nach jeder Änderung an diesen Dateien ist ein vollständiger Clean-Build nötig, da die Engine-Auswahl zur Build-Zeit fest in die native Binärdatei einkompiliert wird und ein einfacher JS-Reload nicht ausreicht.

6. JSI und die New Architecture

Ein weiterer Grund, warum die Hermes Engine heute so zentral für React Native ist, liegt in ihrer engen Integration mit dem JavaScript Interface (JSI). JSI ersetzt die alte, asynchrone Bridge, über die JavaScript und nativer Code früher ausschließlich über serialisierte JSON-Nachrichten kommunizierten. Mit JSI können native Objekte direkt als Referenzen in JavaScript gehalten werden, wodurch synchrone Aufrufe zwischen beiden Welten möglich werden, ohne Serialisierungs-Overhead.

Hermes wurde von Anfang an mit JSI-Kompatibilität konzipiert und ist damit ideal für TurboModules und den Fabric-Renderer der New Architecture geeignet. Während JSC nachträglich JSI-fähig gemacht werden musste, ist die enge Integration bei Hermes ein nativer Bestandteil des Designs, was sich in geringerem Overhead bei häufigen Cross-Language-Aufrufen niederschlägt.

Für Teams, die auf die New Architecture migrieren, ist die Kombination aus Hermes und JSI kein optionales Detail, sondern die Grundlage, auf der TurboModules überhaupt performant funktionieren. Wer noch auf JSC setzt, verliert einen Teil der Effizienzgewinne, die JSI eigentlich bieten soll, weil die Brücke zwischen Engine und nativem Code dort mit mehr Anpassungsaufwand verbunden ist.

7. Debugging von Hermes-Apps

Debugging mit der Hermes Engine funktioniert über das Chrome-DevTools-Protokoll, das Hermes nativ unterstützt. Entwickler können Breakpoints setzen, Variablen inspizieren und den Call-Stack durchsuchen, ähnlich wie bei der Web-Entwicklung. Der große Unterschied zu einer klassischen Remote-Debugging-Sitzung: Der JavaScript-Code läuft weiterhin direkt auf dem Gerät oder Simulator, nicht in einer separaten Chrome-Instanz, was das Timing-Verhalten realistischer macht.

Für Produktions-Crashes ist die Symbolisierung über Source Maps entscheidend. Da ausgelieferter Code als Bytecode vorliegt, sind Stack-Traces ohne Source Maps praktisch nutzlos, sie zeigen nur Bytecode-Offsets statt lesbarer Funktionsnamen und Zeilennummern. Ein häufiger Fehler in CI/CD-Pipelines ist, die von hermesc erzeugten Source Maps nicht konsequent an den Crash-Reporting-Dienst hochzuladen, wodurch Produktions-Crashreports unbrauchbar werden.

Ein solides Setup lädt die Source-Map-Datei bei jedem Release automatisch zum Crash-Reporting-Tool hoch und verknüpft sie mit der jeweiligen Build-Nummer. Ohne diesen Schritt bleibt selbst die stabilste Hermes Engine-Konfiguration bei echten Produktionsfehlern schwer zu debuggen, weil die eigentliche Fehlerursache im Bytecode verborgen bleibt.

8. Grenzen von Hermes und der Blick auf Static Hermes

Die Hermes Engine ist nicht in jedem Szenario die überlegene Wahl. In frühen Versionen fehlten einzelne Intl-API-Funktionen für Internationalisierung, was mittlerweile weitgehend nachgerüstet wurde, aber bei sehr alten Hermes-Versionen noch relevant sein kann. Manche Debugging-Workflows, insbesondere solche, die stark auf spezifische JSC-Werkzeuge angewiesen sind, funktionieren mit Hermes nicht identisch, auch wenn das Chrome-DevTools-Protokoll die meisten Use Cases abdeckt.

Die eigentlich spannende Entwicklung ist Static Hermes, ein von Meta angekündigtes Projekt, das JavaScript nicht nur in Bytecode, sondern direkt in nativen Maschinencode vorkompiliert. Das würde den Interpretationsschritt zur Laufzeit komplett entfallen lassen und Performance-Charakteristiken erreichen, die klassischer JIT-Compilation nahekommen, ohne deren Laufzeit-Overhead beim App-Start.

Für die meisten produktiven Apps heute bleibt die Standard-Hermes Engine jedoch die richtige, gut getestete Wahl. Static Hermes ist ein Ausblick auf die nächste Evolutionsstufe, aber noch kein Ersatz für die aktuell ausgelieferte, stabile Bytecode-Variante, die in Millionen produktiver React-Native-Apps läuft.

9. Hermes im Vergleich: JSC, V8 und Hermes

Die Wahl der JavaScript-Engine hat direkte Auswirkungen auf Startzeit, Speicherverbrauch und Debugging-Erfahrung. Die folgende Übersicht vergleicht die drei relevanten Engines im mobilen React-Native-Kontext.

Kriterium Hermes JavaScriptCore (JSC) V8
Kompilierungsmodell AOT-Bytecode beim Build JIT zur Laufzeit JIT zur Laufzeit
App-Start (Low-End-Android) Sehr schnell Langsamer durch Parsing In RN nicht produktiv genutzt
Speicherverbrauch Gering, generationelle GC Höher Höher, für Desktop optimiert
JSI-Integration Nativ konzipiert Nachgerüstet Nicht relevant für RN
Standard in React Native Ja, seit RN 0.70 Vorheriger Standard Nein

Die Tabelle macht deutlich, warum sich Meta für Hermes als Standard entschieden hat: Die Kombination aus AOT-Bytecode, geringerem Speicherverbrauch und nativer JSI-Unterstützung passt exakt zu den Anforderungen mobiler Apps, während JSC seine Stärken eher in Browser- und Desktop-Umgebungen ausspielt, für die es ursprünglich entwickelt wurde.

Mironsoft

React-Native-Performance-Audits und App-Optimierung

App-Start und Speicherverbrauch professionell optimieren?

Wir analysieren eure React-Native-App auf Engine-Konfiguration, Bytecode-Setup und Speicherverhalten und sorgen dafür, dass die Hermes Engine ihr volles Performance-Potenzial ausschöpft, von der Build-Pipeline bis zum Crash-Reporting.

Engine-Audit

Prüfung von Hermes-Konfiguration, Bytecode-Build und Source-Map-Pipeline

Startup-Optimierung

Time-to-Interactive messen und gezielt auf Low-End-Geräten verbessern

Crash-Reporting

Source-Map-Upload und Symbolisierung für belastbare Produktions-Diagnosen

10. Zusammenfassung

Die Hermes Engine beschleunigt React-Native-Apps, weil sie den teuersten Schritt eines App-Starts, das Parsen von JavaScript, vom Gerät des Nutzers in die Build-Pipeline verlagert. AOT-Bytecode-Kompilierung, ein generationeller Garbage Collector und native JSI-Integration sorgen zusammen für kürzere Time-to-Interactive, geringeren Speicherverbrauch und weniger GC-bedingte Ruckler, besonders auf Low-End-Android-Geräten, die den größten Teil der globalen Nutzerbasis ausmachen.

Die praktische Einrichtung ist seit React Native 0.70 meist keine eigene Aufgabe mehr, da Hermes Standard ist. Wichtig bleibt die konsequente Verifikation über HermesInternal, eine funktionierende Source-Map-Pipeline fürs Crash-Reporting und das Bewusstsein für die wenigen verbleibenden Grenzen der Engine. Mit Static Hermes zeichnet sich bereits die nächste Evolutionsstufe ab, die den Interpretationsschritt vollständig eliminieren könnte.

Hermes Engine in React Native: Das Wichtigste auf einen Blick

AOT-Bytecode

JavaScript wird beim Build mit hermesc in Bytecode kompiliert, nicht erst beim App-Start geparst.

Schnellerer Start

Kürzere Time-to-Interactive, besonders spürbar auf Low-End-Android-Geräten mit schwacher CPU.

Generationelle GC

Kurzlebige Objekte werden effizient verwaltet, weniger OOM-Abstürze und GC-Ruckler.

JSI & New Architecture

Native JSI-Integration ist Grundlage für performante TurboModules und Fabric-Renderer.

11. FAQ: Hermes Engine in React Native

1Was ist die Hermes Engine?
Eine von Meta entwickelte JS-Engine, die JavaScript beim Build in Bytecode kompiliert statt es zur Laufzeit zu parsen. Standard seit React Native 0.70.
2Warum ist Hermes schneller als JSC?
Parsing passiert beim Build, nicht beim App-Start. Beim Start muss nur fertiger Bytecode geladen werden, was besonders auf langsameren Geräten Zeit spart.
3Wie prüfe ich ob Hermes aktiv ist?
global.HermesInternal abfragen: existiert das Objekt, läuft Hermes. Fehlt es, ist die App auf die klassische Engine zurückgefallen.
4Muss ich Code für Hermes anpassen?
In der Regel nein. Moderne JavaScript-Features werden weitgehend unterstützt, frühere Intl-API-Lücken wurden größtenteils geschlossen.
5Warum verbessert Hermes den Speicherverbrauch?
Ein generationeller Garbage Collector verwaltet kurzlebige Objekte effizient, was OOM-Abstürze und GC-Ruckler reduziert.
6Was ist JSI und die Verbindung zu Hermes?
JSI ersetzt die alte asynchrone Bridge durch direkte Referenzen. Hermes wurde von Anfang an JSI-kompatibel konzipiert, ideal für TurboModules und Fabric.
7Warum sind Crashreports unlesbar?
Ohne Source Maps zeigen Crashreports nur Bytecode-Offsets. Die Source-Map-Datei muss bei jedem Release an den Crash-Reporting-Dienst hochgeladen werden.
8Was ist Static Hermes?
Ein angekündigtes Projekt, das JavaScript direkt in nativen Maschinencode statt in Bytecode kompiliert und den Interpretationsschritt zur Laufzeit eliminiert.
9Wie aktiviere ich Hermes in Expo?
In app.json "jsEngine": "hermes" setzen, global oder pro Plattform. Seit React Native 0.70 ist es ohnehin Standard.
10Wo profitiert Hermes am meisten?
Auf Low-End-Android-Geräten mit begrenztem RAM und schwacher CPU. Auf leistungsstarken iPhones ist der Unterschied oft kaum wahrnehmbar.