Multiple Runtimes, Reducing Your Claude Code Bill, and Marie Kondo-ing a Monorepo

Issue #4408 June 20266 Minutes
0.dr-stange-meme-square.jpeg

Please! Give the Chat Screen Its Own Brain

JavaScript runs on a single thread. One.

It has worked this way since the dawn of time 1995.

And it has the throughput of a single open checkout lane on Saturday before Christmas.

react-native-runtimes, from Margelo and built with Callstack, gives React Native access to more than one runtime. Before that lands, it helps to clear something up: threads and runtimes are not the same thing, even though they often get mixed together.

Let’s unpack that.

A thread is an OS (Operating System) level execution lane, and the CPU can schedule many in parallel.

A runtime is a software construct: an instance of a JS engine, for example Hermes, with its own heap, call stack, global object, and garbage collector. A runtime executes on a thread, and in practice one JS runtime is pinned to one thread.

React Native gives your code exactly one of these runtimes, and it sits on the JS thread.

There are other threads (the UI thread draws your native views and handles gestures), but your app's code shares the same JS runtime.

So your navigation, your reducers, your data hydration, and that one chat screen with 4,000 messages all queue up for it. When the chat screen mounts and hydrates everything at once, the rest of your JavaScript stands politely behind it and waits.

The user calls this "lag". We call it Tuesday.

The Margelo team plugged react-native-runtimes into MetaMask, which made the app start substantially faster:

1.margelo-metamask-demo.gif

Here is the part that feels illegal.

You wrap the heavy component in a single tag:

import { OnRuntime } from '@react-native-runtimes/core';

<OnRuntime name="feed-runtime">
  <HeavyFeedList userId={userId} />
</OnRuntime>

At build time, Metro rewrites that JSX into a registered "threaded boundary" and ships it off to a secondary runtime. The main runtime stays free for navigation, gestures, and the rest of your UI.

Now the catch…

Separate runtimes mean separate memory heaps (the pile of memory where a runtime keeps its objects), and the two heaps never touch. An object created on the chat runtime lives only in the chat runtime's heap.

The main runtime cannot see it, point at it, or read it, because the two share no memory.

You cannot share an object between runtimes; anything that crosses gets copied.

Every cross-runtime call turns its arguments into a JSON string on the way out and rebuilds that string into a brand-new object on the other side. Copying a chat ID is nothing (one number), while copying a four-thousand-message array means stringifying and re-parsing all four thousand on every call.

And what arrives is a copy, so changing it on one side changes nothing on the other.

Thankfully, the Formula 1 team Margelo saw this coming and also shipped @react-native-runtimes/state, which is a Zustand-style store backed by a native C++ singleton. The state sits down in native land, underneath all the JavaScript heaps, so every runtime reads and writes it synchronously.

// chatStore.ts
import {
  createSharedStore,
} from '@react-native-runtimes/state';

// One store, kept in native C++ so every
// runtime sees the same value.
export const chatStore = createSharedStore({
  name: 'chat',
  initialState: { messages: [] },
});

// A path handle points at one slice of state.
const messages = chatStore.path(['messages']);

// Any runtime subscribes to that slice...
const list = messages.use(value => value ?? []);

// ...and any runtime writes the same slice.
await messages.update(p => [...(p ?? []), msg]);

The heavy work moves off the main lane, and shared data sits in native land where every runtime reads it at full speed, no four-thousand-message array stringified on every call.

The result is a feed, chat, or wallet that boots without freezing the screen in front of you.

Anywhere one expensive chunk of JavaScript has been holding the rest of your app hostage, a second runtime pays for itself.

Your chat screen will still throw its four-thousand-message tantrum on mount.

It just throws it alone now, on its own runtime, where no user can hear it scream.

👉 React Native Runtimes


2.react-summit-conf-amsterdam.png

The biggest React conference worldwide!

Only a few days left!

We know we say this a lot, but sometimes it is healthy to close the IDE, leave the localhost cave, and meet the humans behind the libraries.

React Summit is happening on June 12 & 16, in Amsterdam & online, and the lineup is very much worth paying attention to.

What awaits you there:

60+ speakers, from OSS maintainers to AI tooling pioneers.

Deep dives into Claude Code, Cursor, React Server Components, TanStack, full-stack architecture, career growth, and the topics shaping where React is going next.

On the lineup: Scott Tolinski from Syntax.fm, Dominik Dorfmeister from React Query, Mark Erikson from Redux, Manuel Schiller from TanStack Router & Start, Aleksei Petrov, Anthropic Claude ambassador, and many more.

There will also be Amsterdam boat tours, riverside food trucks, and an after-party, because even frontend developers deserve sunlight occasionally.Aaaand we’ll be there!

If you see us, come say hi. We are easier to debug in person. Sometimes. Most times.

Can’t make it to Amsterdam? You can join remotely too.

🎟️ Grab your hybrid or online ticket with 15% off using promo code we sent to your email:

👉 reactsummit.com


3.of-mice-and-men-ai-meme.jpg

60% Off Every Token Your Agent Reads

Let's get the awkward part out of the way.

We are about to talk about a tool written 77% in Python and 18% in Rust, no <View> in sight.

We held out for a while.

We told ourselves we were a React Native newsletter, a proud chronicler of Reanimated releases and the occasional build.gradle war crime. But you all run Claude Code on your RN monorepos now; you let an agent read 80,000 tokens of node_modules to fix one import.

So here we are.

We are also an AI newsletter now. Pour one out.

Headroom by Tejas Chopra (@chopratejas), a Netflix engineer who got tired of setting money on fire in Claude Code, is a context compression layer for AI agents. It compresses everything your agent reads (tool outputs, logs, files, conversation history) before it reaches the model, and claims 60 to 95% fewer tokens for the same answer.

4.headroom-dashboard-demo.gif

Here's the part that makes it more than a fancy .slice().

Headroom sits between your agent and the model and works in three moves.

First, it looks at each chunk coming through and compresses it based on its type, since code, JSON, and logs all compress differently.

Second, it keeps the unchanging start of your prompt byte-for-byte identical, because providers cache that opening stretch and bill less for it on every later turn, and one stray edit throws the discount away.

Third, and this is the one that matters, it never actually deletes the original: the full text stays on your machine, and the model gets a headroom_retrieve tool, so if the agent really needs what got compressed, it just asks for it back.

5.headroom-pipeline-diagram.jpg

Getting started is a few lines, and it wraps the agent you already run:

# 1. Install
pip install "headroom-ai[all]"   # Python
npm install headroom-ai          # Node / TS

# 2. Pick a mode
headroom wrap claude      # wrap a coding agent
headroom proxy --port 8787  # proxy, no code changes
from headroom import compress  # or inline in code

# 3. See the savings
headroom perf

Anyway.

Next issue we're back to React Native.

Assuming our agent hasn't compressed the entire newsletter down to "RN good, ship it."

👉 Headroom


6.when_you_use_expo_dog.jpg

Madam, The Doctor Will See Your Codebase Now

Aiden Bai (@aidenybai), the mind behind React Scan, has shipped React Doctor.

Art your project root, you can run:

npx react-doctor@latest

It scans the entire codebase and hands back a score out of 100.

A number representing everything you did wrong.

Like an annual physical, except the waiting room is your terminal.

7.doctor-ezgif.com-optimize.gif

The engine runs 376 rules.

29 of those are React Native specific.

A reanimated rule, rn-animate-layout-property, that catches marginLeft inside withTiming, where every frame forces a layout recompute on the JS thread.

rn-no-inline-flatlist-renderitem flags inline arrow functions in renderItem that allocate a new closure per row. AKA, that is bad.

rn-no-scrollview-mapped-list spots the ScrollView with .map() that should be a FlatList. Also bad, score minus minus boy.

rn-no-falsy-and-render catches {count && <View/>} before it renders a literal zero to the screen.

These are the bugs that survive code review because they look correct.

The part that matters right now is the agent skill.

Run react-doctor install, and it writes a skill file into your project that tells Claude Code, Cursor, or Codex to run react-doctor --verbose --diff after every code change.

Claude Code and Cursor take this a step further with native lifecycle hooks, which are scripts that fire automatically when the agent edits a file.

Run react-doctor install --agent-hooks, and React Doctor registers itself as one of those hooks, so every time the agent saves a change, the scan runs and the diagnostics are returned to the agent's context before it moves on to the next task.

The agent that wrote the bad code gets the feedback before you even see it.

Oh, and the rule design-no-em-dash-in-jsx-text flags em (-) dashes in JSX copy.

We have never felt so seen.

👉 React Doctor

8.bye44-ezgif.com-optimize.gif
Gift box

Join 1,000+ React Native developers. Plus perks like free conference tickets, discounts, and other surprises.