Learn Hermes JS Engine - Configuration Management & Build Validation
Episode 11 of 23

Learn Hermes JS Engine - Configuration Management & Build Validation

Discussing how to store Hermes configuration as a single source of truth so builds are reproducible, validate build artifacts in CI, and integrate linting and the release pipeline so every release passes the same checks.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Introduction

Episode 10 closed the observability chain: source maps, readable stack traces, and tidy telemetry. Now we step back to the side nobody sees: how to make sure every build produces the same bytecode, validated, and ready to release. Without this, even a good source map becomes a lie if the build can't be reproduced.

The roadmap for episode 11: storing Hermes configuration for build reproducibility, validating build output with CI checks, then integrating everything with linting and release pipelines.

Hermes Configuration as a Single Source of Truth

The classic team problem: developer A builds with the -O flag, developer B forgets it, and the bytecode produced differs on their machines. The solution is simple — Hermes configuration must be committed code, not memorized commands. In React Native, compiler flags are stored in build.gradle:

app/build.gradle
react {
  hermesFlags = [
    "-O",
    "-output-source-map",
  ]
}

For embeddable workloads outside React Native, store the compile command in a shared script, for example scripts/compile.sh. Never run hermesc ad hoc without documenting the flags. If the configuration changes, that change must be visible in code review like any other code change.

This single source of truth is what makes builds reproducible: as long as everyone uses the same file, the bytecode produced is identical.

Build Reproducibility

Reproducibility isn't enough with just the same flags. Toolchain versions also have to be locked:

  • Pin the Hermes version: follow the Hermes version pinned to the React Native you use, or pin the hermesc commit for custom embedding. Bytecode is locked to the engine version — remember the lesson from episode 13 later.
  • Lockfile: bun.lock or package-lock.json must be in the repo, and CI installs use frozen mode, for example bun install --frozen-lockfile.
  • Version stamping: store the build version into native config metadata, so every artifact can be traced back to its original commit.
versi-toolchain.sh
hermesc -version
node --version
bun --version

Run the three commands above when CI starts, then record the output as part of the build report. When a bug appears, you can distinguish "a problem in the code" from "a problem in the toolchain" just from this record.

Info

Frozen lockfile mode is the first gate of reproducibility: if a dependency isn't recorded, the install fails immediately instead of silently producing different bytecode.

Validating Build Output in CI

A successful build doesn't necessarily mean the output is correct. CI must validate artifacts before they're considered shippable. Minimum checks:

  • The bytecode bundle exists and isn't empty.
  • The source map exists and its pairing is valid.
  • The bytecode can be read by an inspection tool, for example hbcdump.
  • The bundle size hasn't jumped past the agreed budget.

A validation script can be as simple as this:

scripts/validate-artifacts.sh
set -e
test -s dist/index.android.bundle
test -s dist/index.android.map
hbcdump -summary dist/index.android.bundle

If any check fails, the script exits with a non-zero code and CI goes red. Building automated checks like this is much cheaper than finding a broken bundle in the hands of users.

CI Checks and Pipeline

Integration happens in the workflow. Here's an example of the steps commonly used in a Hermes build pipeline:

ci-hermes-checks.yml
name: hermes-build-check
 
on:
  pull_request:
  push:
    branches: [main, staging]
 
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Install dependencies
        run: bun install --frozen-lockfile
      - name: Build bundle
        run: bun run build:content
      - name: Validate artifacts
        run: bash scripts/validate-artifacts.sh
      - name: Upload source maps
        run: bash scripts/upload-sourcemaps.sh

Notice that every pull request already goes through the same flow as a release: locked install, build, validation, and source map upload. This gives the release pipeline no surprises — the kind that usually only show up at the last step before shipping.

Integrating with Linting and Release Pipelines

Build configuration also needs to be maintained through linting. Some proven practices:

  • Lint the configuration: create rules that reject disallowed hermesFlags or a missing source map on release builds.
  • Mandatory release checklist: conventional commits, correct semantic versioning, and validated bytecode artifacts become prerequisites before a release tag is created.
  • Release gates: all CI checks must be green before an rc tag or stable version can be promoted.

A good release pipeline is deterministic: the same sequence runs, the same artifacts are produced, and the go/no-go decision is made by CI, not by human memory.

Conclusion

With configuration stored as code, a locked toolchain, and CI validating every artifact, you have a build foundation that's repeatable and trustworthy. Linting and release gates close the loop: nothing ships without passing the same checks.

The essentials to take home:

  • Hermes configuration is stored as code, not as commands memorized in your head.
  • Reproducibility needs consistent flags, locked toolchain versions, and a frozen lockfile.
  • CI must validate artifacts: the bundle exists, the source map is valid, and the bytecode is readable.
  • Source maps are uploaded in the same pipeline as the build, before the app ships.
  • Release gates are decided by a green CI, not by human memory.

In episode 12 we enter a new phase: Secure Runtime Practices. You'll learn to load JavaScript bundles securely, avoid remote code execution and unsafe eval, and practical mitigations for mobile and edge apps. See you there!

Learn Hermes JS Engine - Configuration Management & Build Validation | Learn Hermes JS Engine