CLI tool
facebook/hermes avatar
facebook/hermes

Hermes: React Native's JavaScript engine moves compilation to build time, and now to native code

A JavaScript engine optimized for running React Native.

11,434 stars901 forksJavaScriptMIT

At a glance

What is it?
Hermes compiles JavaScript ahead of time into memory-mapped bytecode, with an optional baseline JIT and a shermes tool that emits native executables. Its typed compilation mode is still unfinished, and its versioning has split into two lines.
Who is it for?
Hermes is the right engine when you ship React Native apps or want to embed a JavaScript runtime that loads precompiled bytecode with little start-up work. It is a poor fit if your code leans on eval reaching local variables, and its typed compilation mode is not ready for use.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • facebook/hermes11,434 ★ · +119
Star history
Repository2026-09-222026-11-13
facebook/hermes11.3k11.4k

119 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Bytecode compiled at build time is the production path

Most engines parse and compile JavaScript on the device every time an app starts. Hermes moves that work to build time. Its compiler parses, analyzes and optimizes the whole program once and emits bytecode that the engine memory-maps and starts executing immediately. Start-up cost, memory use and binary size all benefit, and the optimizer sees the entire program rather than one function at a time. This is how React Native apps use Hermes, and it is the only path that receives all of the optimizations. The engine still contains the compiler, so plain .js files run directly, but that is meant for development. When given source, Hermes compiles it to bytecode before running, and by default it compiles large sources lazily, one function at a time when each is first called. If you ship source instead of bytecode, you give up the build-time whole-program optimization that is the reason the engine exists.

eval and new Function see only the global scope

Hermes supports eval() and new Function(), and both invoke the compiler at runtime. They are intended for small things. Code passed to eval can see only the global scope; it cannot read or write the locals of the function that called it. The project left this out on purpose, because allowing it would force the compiler to pessimize every function in the program. The consequence for porting existing code is concrete: a library or script that builds a string and evals it to reach surrounding local variables will not behave as it does in engines that allow that. Such code has to be rewritten to pass values explicitly or to work against globals before it can run on Hermes.

Four execution modes can share one runtime

Hermes runs JavaScript from source, from bytecode, through an optional baseline JIT, and as native code, and these can be mixed freely in one runtime. The JIT compiles frequently executed functions to machine code while the app runs. It is deliberately simple: the heavy optimization already happened at build time, so the JIT stays small and predictable. Native code comes from the shermes tool, which compiles JavaScript ahead of time with no interpreter involved. An app can ship some modules as native code, some as bytecode, and generate more at runtime, and the JIT will pick up hot functions from the bytecode and runtime-generated code. shermes works on ordinary untyped JavaScript and on typed JavaScript, and the typed input produces much better native code.

Typed compilation strengthens JavaScript semantics, and is not ready yet

Hermes is gaining the ability to use type annotations to compile JavaScript to much faster code. This work is under active development and not ready for use. Flow and TypeScript syntax are both being supported, to different degrees; TypeScript is currently converted to Flow by an AST pass contributed by Amazon, an implementation detail that may change. The hard part is that neither the Flow checker nor the TypeScript compiler guarantees that annotations are true at runtime:

js
const a: number[] = [];
const n: number = a[0]; // the type says number, the value is undefined

Typed Hermes closes that gap by changing behaviour. It range-checks array indexing and throws on out-of-bounds access, and where a value of unknown type flows into a typed one, from any or from untyped code, it inserts a checked cast that throws at runtime on a mismatch. Code that quietly read undefined from past the end of an array under a normal engine will throw under typed compilation, so turning it on is a semantic change, not just a speed switch.

TypeScript's structural typing blocks object layout

TypeScript is less friendly to static compilation than Flow because its typing is structural and it is unsound in more places. This program type-checks in TypeScript and fails at runtime, while Flow rejects it because object properties are invariant:

ts
class Animal {}
class Dog extends Animal { bark() {} }
class Cat extends Animal {}

const d: { pet: Dog } = { pet: new Dog() };
const a: { pet: Animal } = d; // TypeScript accepts, Flow rejects
a.pet = new Cat();
d.pet.bark();                  // d.pet is a Cat: "bark is not a function"

In TypeScript a value of type Dog need not be an instance of Dog; any object with the same shape qualifies. A compiler therefore cannot derive an object layout from a class, and that layout is what makes typed code fast. Separately from typed compilation, TypeScript already runs on Hermes in untyped, unsound mode: annotations are stripped and the result is treated as plain JavaScript, as covered in doc/typescript-stripping.md.

static_h became the main line, and the version numbers changed with it

Static Hermes was the code name for an umbrella project, developed on the static_h branch, to add static typing and optional native compilation. That branch then became the main development line and is the repository's default branch. It also gained the JIT, modern ECMAScript features and a lot of unrelated work. It is not a separate engine. Releases used to be numbered 0.x. Once static_h was judged ready, its releases moved to a scheme built from the branch date and bytecode version, for example 260318099.0.0, and React Native calls it Hermes V1 to separate it from the legacy line on the main branch. The GitHub releases page does not make this obvious: its newest entries are v0.13.0 for React Native 0.75.x from August 2024, v0.12.0 from August 2022 and v0.11.0 for React Native 0.68.x. Commits continue; the last push was on 31 October 2026. doc/Branches.md explains the split.

Building hermes and shermes wants Clang, not gcc

You need a C++17 compiler, CMake, Ninja and Python. Clang is strongly recommended; gcc is supported but produces noticeably worse code, so a gcc build is not a fair picture of the engine. On Ubuntu:

shell
apt install clang build-essential cmake git ninja-build python3 tzdata libreadline-dev

Clone and build the two command line tools, hermes (compile to bytecode, run bytecode or source) and shermes (compile to native):

shell
git clone https://github.com/facebook/hermes.git
cmake -S hermes -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build build --target hermes shermes

Run a script from source, then from bytecode the way apps do:

shell
echo "print('Hello from Hermes');" > hello.js
build/bin/hermes hello.js
build/bin/hermes -emit-binary -out hello.hbc hello.js
build/bin/hermes hello.hbc

Compile the same script to a native executable:

shell
build/bin/shermes -O -o hello hello.js
./hello

The -emit-binary step is the one that mirrors production; running hello.js directly exercises the development path.

Editorial conclusion

Hermes is the right engine when you ship React Native apps or want to embed a JavaScript runtime that loads precompiled bytecode with little start-up work. It is a poor fit if your code leans on eval reaching local variables, and its typed compilation mode is not ready for use. Before adopting it standalone, check which line you need: the static_h branch with date-based versions that React Native calls Hermes V1, or the legacy 0.x line on main.

Frequently asked questions

How do I use Hermes to run a JavaScript file?

Build the hermes tool and run build/bin/hermes hello.js for source, or compile with build/bin/hermes -emit-binary -out hello.hbc hello.js and run the .hbc file, which is how apps use Hermes.

How do I install Hermes?

Hermes is built from source with a C++17 compiler, CMake, Ninja and Python, with Clang strongly recommended. Clone facebook/hermes, configure with cmake using Ninja, and build the hermes and shermes targets.

Is Static Hermes a different engine from Hermes?

No. Static Hermes was the code name for work on the static_h branch, which became the main development line; React Native calls its releases Hermes V1.

Can Hermes run TypeScript?

Yes, in untyped mode: annotations are stripped and the code runs as plain JavaScript. Typed compilation that uses TypeScript annotations for speed is under development and not ready for use.

Official sources

  1. facebook/hermes on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/facebook-hermes.svg)](https://hysenlabs.com/projects/facebook-hermes)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/facebook-hermes.svg)](https://hysenlabs.com/projects/facebook-hermes)

Was this useful?