Curated reading
164 deep-dives, every one fetch-verified and annotated with why it matters — organized by the decision it informs, not by publish date. The annotations are our editorial take; the articles are the originals — read them there. A piece lands here only if it's the canonical explanation for its topic; how-to content routes to depth skills instead.
React & language foundations
react-core — React core — version, Compiler, RSC, concurrent features
The hidden cost of React.Activity
The when-NOT-to caveat behind this entry's <Activity> row: hiding preserves STATE but destroys and re-creates EFFECTS on every toggle — so effect-shaped work (keyboard subscriptions, analytics, listeners) piles up subscription/setState waves each time a hidden RN screen is shown again.
Pair <Activity> with disciplined effect cleanup or don't use it for effect-heavy subtrees.
How to Build the Fastest Apps: Break the Rules (App.js Conf 2026)
Reframes rendering cost as the dominant hidden bottleneck: React's `render` doesn't just paint — it passes state down, updates context consumers, fires effects, and re-subscribes queries, so ordinary patterns (lift-state-up, effects-for-coordination, `useContext` on a whole value, deps-array callbacks) cascade renders top-down (measured ~10x CPU top-vs-leaf).
The React Compiler can't save you when a prop *actually* changes. The prescribed toolkit — `useEffectEvent`/stable event callbacks (no deps-array cascades), imperative APIs over hooks (get-a-value + subscribe instead of re-render), `use-context-selector`, and providing *stable* objects through Context — extends the Erikson rendering guide below into a 'render once' discipline. Vendor angle (pitches Legend State), but the render-model reasoning is framework-agnostic. See RB-E-STATE for the state-architecture half.
A (Mostly) Complete Guide to React Rendering Behavior
The end-to-end explanation of when and why React renders — render vs commit, reconciliation, the cascade to children, memo/useMemo/useCallback, Context behavior.
The mental model that makes the React Compiler's auto-memoization comprehensible rather than magic.
Writing Custom Renderers for React
How React's reconciler connects to a host environment (the renderer interface), and why React Native Testing Library needed its own renderer.
The canonical explanation of React's renderer architecture.
Component Architecture for React Server Components
Traces the move from useEffect/React-Query/route-loaders to component-level RSC data fetching, with durable principles: component autonomy, deliberate Suspense boundaries, skeleton co-location.
RSC architecture from a recognized educator.
Building Bulletproof React Components
Ten component-design patterns for SSR/hydration, multiple instances, concurrent rendering, portals, view transitions, and tainting (useId, React.cache, taintUniqueValue).
A durable component-API mental model from an authoritative author.
Understanding why React Fiber exists
Traces React 15's non-interruptible recursive reconciliation to Fiber's linked-list + time-slicing design — the 'why it exists' explainer for concurrent React.
First in a React-internals series (key-prop, state-updates, out-of-order streaming also available).
How does React Fiber render your UI
A first-principles walk through Fiber's four phases (trigger/schedule/render/commit), the fiber-node shape, time-slicing, and the bitmask lane-priority system.
Durable internals knowledge that survives version churn.
Two React design choices developers don't like (but can't avoid)
A competing-framework author argues deferred state commits and effect dependency arrays are forced by async UI, not arbitrary — even signal-based frameworks hit the same wall.
An unusually credible mental model for React's most-griped-about choices.
The React Compiler (explained via its actual output)
You hand-memoize without the React Compiler — this shows the emitted cache-slot output that replaces useMemo/useCallback (and memoizes where hooks can't, e.g. behind early returns); the concrete before/after for adopting it.
The what-does-it-actually-emit explainer the other compiler readings skip: a TodoList compiled into cache-slot code (_c() slots + reference-equality checks — a custom caching system, NOT inserted useMemo/useCallback), dependencies inferred from code FLOW rather than manual arrays, memoization applied where hooks are prohibited (behind early returns), and why identical cached JSX objects stop child re-renders without memo wrappers. Plus a staged adoption path (gradual gating, canary) grounded in Meta/Sanity/Wakelet production numbers. Pairs with the saschb2b retrospective (adoption/bail-outs) — this one is the transformation mechanics.
Props, Composers, and Providers: the composition pattern we're converging on
You create Context in many files — climb the composition ladder instead of reaching for providers by default: plain props, then compound components with slots, and only then a Composer + Providers, each rung justified by a named pain.
The composition facet these readings otherwise skip — they explain how React RENDERS, this explains how to SHAPE a component API as an app grows. A production team's four-rung ladder with the named pain that justifies each climb: plain props (where most components should stay) → compound components with slots (when a row sprouts a prop for every shape) → a Composer plus Providers (when the same UI must render data from swappable or deferred sources) → lifted state behind a contract (when state must cross a boundary and the layout should stay pure). The first two rungs use no context at all. Its governing rule is the useful one: an abstraction earns its place by making a CURRENT requirement simpler, never by betting on a future you can't see.
React Compiler at Eighteen Months
You ship the React Compiler — know the bail-out patterns and keep existing useMemo/useCallback in place (removal can change compiler output); this retrospective is the staged-adoption map.
An 18-month retrospective: how auto-memoization retired the missing-dependency bug class, the five patterns where the compiler bails out, and a staged adoption path. The mental model for the compiler era (complements the official release post in sources).
rn-versions — React Native release timeline — what each version changed
React Native Architecture: From Bridge to Fabric
Traces RN's architecture from the old async JSON bridge to the New Architecture (JSI, Fabric's immutable C++ shadow tree, Turbo Modules, Codegen), explaining why each piece exists.
The 'why it changed' narrative behind the 0.76→0.82 version arc — not a release note.
typescript — TypeScript rigor & public API typing
Migrating a Large Flow Monorepo to TypeScript
You still run Flow — exiting it is a package-by-package program, not a codemod: keep type integrity throughout (flowgen turns emitted .d.ts back into Flow headers), convert deepest dependencies first, and expect uptake to stall until deadlines land.
The receipt under this entry's 'not at Meta → use TypeScript, not Flow' line, and the shape of a type-checker migration you cannot do in one cut: 1.4M SLoC across 570 packages, three years and seven months, ending February 2026. The load-bearing decision was refusing to suspend type-checking anywhere — 'code that loses coverage from its type checker, tests, or linter almost never regains it' — which ruled out a big-bang rewrite and forced Flow and TypeScript to coexist in production. The mechanism: convert one package at a time (flowts first, later Stripe's flow-to-typescript-codemod, which cut the manual tail), then run flowgen to turn the emitted .d.ts back into Flow headers so still-Flow consumers keep type-checking. Because no tool generates .d.ts FROM Flow, the order is forced — deepest internal dependencies first, up the tree. What actually moved the needle was not tooling: a year of dogfooding on ~90 foundational packages before launch, documentation and outreach, a dependency-graph score that ranked which package unblocks the most others, auto-filed Jira tickets when a package became convertible, and finally hard quarterly deadlines — voluntary migration plateaued once the enthusiasts were done. LLM-driven conversion was tried in 2023 and abandoned as unreliable. Outcome: type coverage 83.15% (Flow) → 96.44% (TS), ~6,000 @ts-expect-error (2,000 of them mass-added when the team auto-suppressed the last few dozen orphaned packages to finish), 82% of surveyed engineers reporting a productivity gain.
Why does tsgo use so much memory?
A heap-level investigation of the Go TypeScript compiler — per-thread Checker duplication, never-freed types, symbol duplication, AST at 45% of heap, plus a fix.
A durable deep-dive on TS7/tsgo internals and its concurrency model's cost.
TypeScript Performance in TanStack Table V9
Concrete techniques to cut type-instantiation cost 62-86% (feature maps, materialized interfaces, in/out variance annotations, explicit type args), with measurements.
The reference for heavy-generics library authors.
Iterating Faster with TypeScript 7
You ship TypeScript — TS 7 (Go-native tsc, ~10x) is stable; migrate incrementally through the TS 6 bridge, then run 6 and 7 side-by-side in CI (VS Code cut type-checking 36s→5s; the blocker was formatter diffs, not type errors).
The production adoption case the tsgo-internals piece lacks: VS Code's ~50-extension codebase cut type-checking 36s→5s (~7x) and editor project-load 60s→10s by migrating INCREMENTALLY — TS 6.0 as a low-churn bridge, then TS 6-and-7 side-by-side in CI (TS 6 still emitting), then esbuild + TS 7 as the default. The surprising blocker wasn't type errors but formatter differences failing pre-commit checks. Evidence that TS 7 (Go-native tsc) is trustworthy for daily use on a large real codebase — if you bridge through TS 6 first.
App architecture — state, data, routing, frameworks
state — Client & server state management
Structural sharing, selectAtom, and why your Jotai atoms re-render too much
You ship Jotai — selectAtom is a trap; decompose objects into primitive atoms and use write-layer structural sharing so atomic state is actually fine-grained (Object.is propagation decides what re-renders).
The first Jotai-specific deep-dive here, for the entry's 'fine-grained atoms → Jotai' clause: Object.is propagation mechanics, why selectAtom is a trap (decompose into primitive atoms instead), and write-layer structural sharing à la React Query. The re-render discipline that makes atomic state actually fine-grained.
How to Build the Fastest Apps: Break the Rules (App.js Conf 2026)
The performance case for signal/observable state.
React's `render` over-orchestrates: `useState`/`useContext` couple state *ownership* with *subscription*, so lifting state up and over-subscribed context cascade re-renders top-down — measured ~10x CPU vs updating one leaf node. The fix ('render once'): create state without subscribing (observables / Reanimated shared values), own it high in the tree, push subscription down so only leaf nodes re-render themselves; provide stable objects through Context so the provider never re-renders; subscribe to derived values, not raw ids. Vendor talk (his own Legend State), but the ownership-vs-subscription principle is framework-agnostic and transfers to Jotai atoms, TanStack Store/Signals, and use-context-selector.
React Query as a State Manager
You ship a client store but no server cache — server state (stale-while-revalidate, invalidation, retries) is a different problem; replicating it in the store is the classic mistake this piece dismantles.
The canonical case for treating server state as its own thing (stale-while-revalidate, staleTime, query-key sharing) so you stop replicating it in a client store. The source of the server-state-vs-client-state split.
Why React Context is Not a State Management Tool
You ship no client store — Context is dependency injection, not state management; every consumer re-renders on any value change, so frequently-changing shared state belongs in a selector-based store.
Draws the precise line between dependency injection (Context), client-state stores (Redux/Zustand), and async/server state — the vocabulary that justifies splitting the problem instead of forcing one tool to do all three.
How is Linear so fast? A technical breakdown
Breakdown of Linear's local-first architecture — IndexedDB as the primary store, optimistic updates, granular observables, aggressive code-splitting, GPU-only animation.
The reference for building instant-feeling client-state apps.
Component Communication Patterns in React Applications
A decision framework for WHERE state should live, keyed by component proximity × data type: props/callbacks for adjacent components, lifted state or composition for siblings, context for slow-changing globals, Zustand for frequently-updated client state, TanStack Query for server data, URL params for view state, events for fire-and-forget.
'Reach for the closest tool that can actually reach the problem, and only move outward when it stops working.' The how-to-choose guide that operationalizes this entry's server-vs-client-vs-view split.
Do we need state management libraries anymore?
You ship a client store — every popular one converges on useSyncExternalStore; know what the primitive gives you for free (and where a hand-rolled selector store loops) so the dependency is bought for ergonomics/devtools, not for the mechanism.
The build-vs-buy answer behind this entry's '~34% use no state library' and 'don't add a lib' clauses. Reads Redux, Zustand, Jotai, MobX and Valtio under the hood and shows they all converge on the SAME React primitive — useSyncExternalStore — then builds a working store from scratch with selectors, showing which three problems the primitive solves for free and where the naive version loops infinitely. The point is not that libraries are useless but that you should know what ~50 lines of understood code buys you before adding a dependency: what you pay for is ergonomics, devtools and middleware, not the subscription mechanism.
The Absolute State of Management
The vocabulary attack on this entry's own subject: Russell argues that Redux, MobX, Zustand — and React itself — don't MANAGE state, they PROPAGATE it, and that real state management is about time and conflicts (the problem CRDTs and sync engines actually solve).
Deliberately provocative, and Redux maintainer Mark Erikson pushed back publicly, so read it as a framing argument rather than a verdict. Its durable value here is a third axis next to the client-vs-server split: when your problem is concurrent edits and reconciliation, no propagation library is the answer — that's the local-first/sync-engine row (TanStack DB, Zero — see RB-E-DATA).
data — Data fetching & caching
Coordinating Optimistic Updates in Next.js
You are deciding whether an RSC/Server-Function app needs TanStack Query or SWR — the test is whether data changes on its OWN (polling, pushes). User-driven writes are served by useActionState + useOptimistic; a client cache means keeping two caches in sync.
Answers the question this entry's 'skip a client cache where you can' clause leaves open — when DO you need one — from the other side: two real apps built without one. The pattern is useActionState as an async reducer holding the confirmed-plus-queued state (React queues Actions, so overlapping writes apply in order instead of racing) with useOptimistic layering the in-flight change on top; rollback needs no reverse-change calculation because when the Transition ends the optimistic layer simply disappears and the server data shows through. Scaling it past one component means lifting the queue and the optimistic state into a context provider so sibling subtrees see the same pending change. The criterion at the end is the durable part: reach for TanStack Query or SWR when the data changes ON ITS OWN (messages arriving while you read), not when it only changes because the user acted (a dragged channel layout) — and be honest that adopting one in an RSC app leaves you coordinating TWO caches, invalidating the server cache inside the Server Function and the client keys in the browser. The author's own closing caveat: reducer + Action queue + optimistic state is a fair amount of wiring.
You ship TanStack Query — the maintainer's guidance is to structure around queryOptions objects, not per-query custom hooks (composable across useQuery/prefetch/suspense).
Maintainer-authored architecture guidance: queryOptions objects (not custom hooks) are THE abstraction layer for queries — composable, framework-portable, and reusable across useQuery/prefetch/suspense call sites. The how-to-structure companion to 'Why You Want React Query'.
You ship TanStack Router — its loader cache is per-route while Query's is global; the maintainer maps when route-loader caching alone suffices and how to layer both without double-fetching.
The selection question this entry's TanStack rows raise: Router's cache is per-route, Query's is global — when route-loader caching alone suffices, when you want the full query cache, and how to layer them without double-fetching. Maintainer-authored.
You ship an HTTP client but no server cache — hand-rolled fetching hides race conditions, StrictMode double-fires, and stale error states; a server cache (TanStack Query) fixes the class.
Takes a naive fetch-in-useEffect and exposes the five real bugs it hides (race conditions, missing loading/empty states, stale data+error pairs, StrictMode double-fire), then shows how a server cache fixes them. The durable answer to why-not-just-useEffect.
From latency to instant: modernizing GitHub Issues navigation performance
Engineering case study on local-first caching, stale-while-revalidate, service-worker hard-navigation, and preheating vs naive prefetch, with measured percentile gains.
Durable client-side data-caching patterns at scale.
The Best Loading States Are No Loading States
Argues loading UI belongs at the app/route level (transitions + preload-on-hover/intersection) rather than scattered component spinners, using blank regions as a preload diagnostic.
Durable, framework-agnostic data-loading-UX thinking.
use(): the hook that breaks the rules (on purpose)
Deep-dive on the use() hook — unwrapping promises/context at render under Suspense, the promise-identity caching requirement, and why it can legally run conditionally unlike other hooks.
The modern data-fetching primitive explained.
Real-time cache invalidation (SSE + tRPC + Redis + BullMQ)
A full architecture for pushing invalidation EVENTS (not data) over SSE to drive TanStack Query cache updates, with reference-counted subscriptions and horizontal-scaling guidance.
The real-time dimension the other DATA readings don't cover.
What Does a GraphQL / Server-State Client Cost You Per Request?
You route high-frequency data (WebSocket ticks, polling) through a server-state client — the cost is per cache write and measurable: on low-end Android, RTK Query billed ~3.2s of JS-thread self-time vs ~0.9s for TanStack Query/Relay.
The only PRICE TAG on this entry's options: one Expo app (SDK 57 / RN 0.86 / React 19, New Arch) built six times behind an identical DataLayer contract against Coinbase's public GraphQL API, Maestro-driven, on a low-end Samsung A16, measured with Flashlight plus a Hermes sampling profiler started at bundle load. Library self-time summed across three flows — Vanilla 0ms, Jotai 122ms, Zustand 277ms, Relay 804ms, TanStack Query 904ms, RTK Query 3218ms. The durable finding is the SHAPE, not the ranking: cost is per CACHE WRITE, so a network response, a live tick and an optimistic update each pay it — RTK Query's number explodes only in the flow with WebSocket price ticks. Pick for the features you need, then keep firehose data out of the expensive path. (Reproducible: AndreiCalazans/GraphqlClientComparison.)
You Should Not Use Relay for Everything
You ship Relay — scope it to cross-referenced entity data: config, experiments, volatile time-series, server-driven UI trees and inlined assets don't benefit from normalization, and a plain store beside Relay is strictly cheaper for them.
The counterweight to this entry's 'Relay for scale' row, from the same author as the cost benchmark above: Relay's normalized store earns its cost only for cross-referenced entities — for client config, index-based experiments, volatile time-series ticks, server-driven UI trees and inlined assets, normalization is pure overhead (an 18MB Relay store profiled in production), and a plain store with its own fetch/refresh/persist policy is strictly cheaper. Scoping guidance, not anti-Relay: use it where cross-entity consistency pays.
p2p — Peer-to-peer / local-first backend (Holepunch · Pear)
Pear by Holepunch — building blocks & architecture (docs)
You ship the Hypercore stack — data is a local append-only log merged by Autobase, indexed in Hyperbee, synced over Hyperswarm; a conventional client cache/REST layer is N/A by design, and these docs are the canonical reference.
The canonical reference for the Holepunch stack — Hypercore (append-only log), Autobase (multiwriter), Hyperbee (B-tree index), Hyperswarm/HyperDHT (discovery), Hyperdrive (files), Corestore, and the Pear runtime. The 'why' behind P2P/local-first; pair with the holepunch-p2p-systems skill for build/review depth.
nav — Navigation & routing
Detour: deferred deep linking done right in Expo Router
You ship invite or referral links into Expo Router — a plain deep link does NOT survive the store install, so first-launch intent needs deferred deep linking with a server behind it; resolve it in +native-intent.tsx and hold it across your auth gate.
Names a hole every referral/invite flow eventually falls into: standard deep links (Universal Links / App Links) only work when the app is ALREADY installed — iOS and Android preserve nothing across the store boundary, so a new user who taps an invite link launches the app blind to what they clicked. That is the Installation Gap, and closing it needs a server that remembers the click, which is why this has historically meant adopting an attribution SDK (deep linking as its side feature) and hand-writing glue between its callback and your router. The router-side argument is the durable part: because Expo Router exposes `+native-intent.tsx` as pre-routing middleware (redirectSystemPath), the deferred link can be resolved BEFORE the first screen mounts, which removes the post-mount useEffect race, duplicate navigation events and the ordering problem with auth gates; the remaining case — link resolves, user isn't signed in yet, guard redirects to /login and swallows it — is handled by holding the intent in a provider until the app says the user is ready. Vendor content (SWM's own SDK, @swmansion/react-native-detour 2.3.1, and it needs a Detour account for app credentials), but the failure mode and the +native-intent hook are general.
Reverse Engineering ChatGPT Web: How OpenAI Built for a Billion Users
You ship React Router — it runs ChatGPT's web app at billion-user scale (framework mode + streaming SSR), so the stack choice is production-proven; the teardown shows what a tuned RR7 deployment looks like.
Production evidence for React Router 7 framework mode at billion-user scale: ChatGPT migrated Next.js Pages Router → Remix (2024) → RR7 with streaming SSR, TanStack Query seeded from server render, Tailwind 4 tokens, ProseMirror composer — 84KB HTML document, 50-65ms TTFB. The concrete counterweight to 'serious apps need Next.js', and the highest-profile data point behind this entry's React Router when-clause. (4 independent newsletter signals in one week.)
TanStack Router's New Reactive Core: A Signal Graph
The primary source behind this entry's 'signal-based core' claim: the monolithic router.state was decomposed into a graph of independent stores so route changes update only affected subscribers (React navigation 7ms→4.5ms in their measurements).
The architecture under TanStack Router's fine-grained reactivity.
Exploring Inlined Requires: does Expo Router give you screen-level lazy loading?
You ship Expo Router — screens are lazy-loaded by construction, but layouts and the initial route load eagerly and it's sync require, not bundle-splitting; know the mechanism before optimizing startup.
Instrumented proof that Expo Router defers screen loading by construction via require.context() getters wrapped in getComponent thunks — with the precise caveats (layouts/initial route load eagerly; sync require, not bundle-splitting). The canonical explanation of Expo Router's lazy-loading mechanism.
React Router loaders and actions as integration points
You ship React Router — treat loaders/actions as the HTTP-to-domain seam: keep business logic in testable services and reserve loaders/actions for the integration layer, tested E2E.
Frames loaders/actions as the HTTP-to-domain seam — keep business logic in testable services, reserve loaders/actions for the integration layer (E2E). A durable testing/architecture philosophy for React Router.
Deep Links With Authentication in React Navigation
You ship React Navigation — if deep links can land behind auth, the maintainer's routeNamesChangeBehavior 'lastUnhandled' pattern replaces hand-rolled redirect-after-login plumbing.
The redirect-after-login problem: a deep link that lands on the login screen should still deliver the user to the intended screen afterwards. Walks the manual approaches in older React Navigation and the new API that handles it (routeNamesChangeBehavior 'lastUnhandled' re-dispatching the unhandled link when auth state flips). From the library's own maintainer.
Migrating to native stack navigation, with a surprise from iOS 26
You ship React Navigation — native-stack applies platform constraints JS-stack merely tolerated: iOS 26 Liquid Glass is inherited (UIDesignRequiresCompatibility opts out) and the 44pt native bar clips taller header content.
The JS-stack-vs-native-stack behavioral difference no other reading here covers, learned in a real 0.77→New-Arch migration: moving to native-stack means the REAL platform components apply — the app suddenly inherited iOS 26 Liquid Glass styling (opt out with UIDesignRequiresCompatibility in Info.plist while unready), and a 55pt header logo got clipped because the native bar is a hard 44pt. The durable frame: JS-stack headers merely TOLERATED overflow the platform never allowed; native-stack enforces what iOS actually permits, so audit header content heights when migrating. (Live URL is bot-walled — content verified via Wayback snapshot 2026-07-15.)
Untangling Dialogs in React Router
You ship React Router — model modal dialogs as nested routes instead of local useState/useEffect; revalidation, view transitions, flash sessions, and exit animations then ride the router.
Models modal dialogs as nested routes in React Router 7 instead of local useState/useEffect — covering revalidation, view transitions, flash sessions, and exit animations. A durable routing pattern that generalizes beyond the example.
meta-frameworks — Meta-frameworks (full-stack React)
Who Owns the Tree? RSC as a Protocol, Not an Architecture
Argues RSC is a serialization protocol that enables both server-owned and client-owned trees, contrasting TanStack Start's inversion-of-control with Next.js's server-owned model.
The durable mental model for reasoning about RSC across frameworks.
React Server Components in TanStack
You ship TanStack Start — its RSC model is explicit (createServerFn, renderServerComponent) and still EXPERIMENTAL into early v1; this grounds what Start's RSC actually buys (use-case scoping, bundle-size results) before you lean on it.
First-principles RSC tutorial grounded in TanStack Start's explicit API (createServerFn, renderServerComponent), contrasted with Next.js's implicit model, with honest use-case scoping and bundle-size results.
Moving Railway's frontend off Next.js
You ship Next.js — Railway's 200+-route migration to Vite + TanStack Start (10min→<2min builds) is the concrete decision case for when a client-centric app outgrows a server-first meta-framework.
Migration postmortem — 200+ routes off Next.js onto Vite + TanStack Start (10min→<2min builds), with the reasoning for when a client-centric app outgrows a server-first meta-framework. A concrete decision case study.
You ship Next.js — 'use client' does NOT disable SSR; its real costs are bundle, hydration, and fetch waterfalls, and the server-component-as-prop technique keeps subtrees on the server.
The mental model for the use-client boundary — it does NOT disable SSR — plus its three real costs (bundle, hydration, fetch waterfalls), with measured comparisons and the server-component-as-prop technique. Durable RSC fundamentals.
Next.js 16.3: Instant Navigations (16.3 Preview)
How Next.js closes RSC's biggest UX gap — slow navigations — with Cache Components + a per-route Stream/Cache/Block choice and Partial Prefetching (one reusable per-route shell instead of a prefetch per link).
The durable mental model for server-driven-but-instant navigation; covers a facet the other RSC readings don't. Gated behind cacheComponents/partialPrefetching flags (16.3 Preview, not yet stable — verify before quoting as GA).
We Stopped Using RSC on TanStack.com
You ship RSC — its clearest concrete benefit is keeping heavy server-only dependencies out of the browser; TanStack's reversal shows that when the dependency itself gets small, plain SSR keeps the performance win without the architecture cost.
The reversal of the adoption post this entry already cites in sources — read them as a pair. RSC did work: moving markdown + Shiki highlighting to the server cut client JS by ~153KB gzipped on blog/docs pages, took /blog/react-server-components from Lighthouse 52→74 and TBT 1,200ms→260ms. The reversal argument is that the win came from KEEPING A HUGE DEPENDENCY OUT OF THE BROWSER, not from the architecture: once they replaced the 358KiB markdown/highlighting stack with small purpose-built packages (~27KiB transferred, only ~18–19KiB more than the RSC version), plain SSR + server functions held the performance and the RSC machinery — bundler config, serialization boundaries, special files, runtime-boundary rules — was left with nothing to pay for. The honest context-key for 'how much RSC do you actually need': measure whether your case is a dependency problem before you make it an architecture problem.
Different Hydration and Rendering Strategies
A systematic map of the whole rendering spectrum — CSR, SSG, ISR, SSR, streaming SSR + Suspense, RSC, islands, signal-based fine-grained reactivity, Qwik resumability, and Next 16.3 instant navigations — organized around ONE durable question: the gap between when a page LOOKS ready (HTML painted) and when it WORKS (JS hydrated/executing).
Each strategy is a different trade on that window — ship less JS (islands/RSC), execute it faster (signals), or skip execution (resumability). The mental model that turns 'which meta-framework / rendering mode' into a reasoned choice instead of a checklist; the framing behind this entry's context-keys.
forms — Forms & validation
You ship no form library — often right: React 19 native actions + Zod handle simple forms; a library earns its keep at multi-step wizards, async validation, and field-level re-render isolation. This walks the decision.
The decision arc of this entry in interactive form: a four-jobs mental model (capture, verify, recover, commit), then three archetypes — a React 19 useActionState + server-action + Zod form with no client form lib, a TanStack Form multi-step wizard (schema composition, AbortController async checks), and a field-array editable table with row-level re-render isolation — closing with when native React 19 suffices vs when a client library earns its keep. Covers the native-actions end of the spectrum the other reading here doesn't.
React Hook Form Avoids State. TanStack Form Scopes It.
You ship React Hook Form or TanStack Form — the split is where keystrokes land: RHF keeps them out of React's render loop, TanStack Form stores them with narrow subscriptions. Both stay fast; a working RHF form is rarely worth rewriting.
The mechanism behind this entry's RHF-vs-TanStack-Form choice, which the option rows only assert. RHF starts from REGISTERED inputs — the browser holds the value, so ordinary keystrokes never enter React's render loop — and adds React subscriptions only where other UI needs form state. TanStack Form starts from fields backed by a store: inputs are controlled, but only the field and its subscribers update. Both stay fast; they differ in where the default lands, and the post walks the specific code paths where that shows (field binding, watch/subscribe, arrays, async validation). Its own conclusion is the conservative one — a working RHF form is rarely worth rewriting. Examples checked against react-hook-form 7.82.0 and @tanstack/react-form 1.33.1.
One core, six frameworks, zero runtime abstraction
Shows build-time framework abstraction (a tiny core swapped by a bundler plugin) instead of a runtime adapter layer, so form state uses each framework's native signals.
A generalizable library-design pattern reframing portability vs integration.
auth — Authentication & identity — sessions, OAuth, managed vs self-hosted
The free, open, community-maintained guideline for implementing auth from first principles — server-side tokens, sessions, password auth + reset, email verification, OAuth, MFA, WebAuthn, CSRF, open redirects — meant to be read alongside the OWASP cheat sheets.
THE canonical reference when you hand-roll any part of auth instead of adopting a library above; its author sunset the Lucia auth library INTO this book, the lesson being that auth is a design problem more than a dependency.
Sign in with Google for React Native
You ship Google sign-in on Android — the legacy GoogleSignInClient API is deprecated and will be removed; audit whether your RN library targets Credential Manager, and remember the library only gets you the credential, not session handling.
Carries a PLATFORM deprecation this entry had no home for: Android's legacy GoogleSignInClient (Google Play services) is deprecated and slated for removal, with Credential Manager as the replacement — and much of the existing RN Google-sign-in field still targets the old API, so it misses Credential Manager's bottom-sheet flow, automatic sign-in and structured error handling. The post introduces the authors' own @thoughtbot/react-native-social-auth (Credential Manager on Android, Google Sign-In SDK 8+ on iOS with Firebase App Check and custom nonces, TypeScript-first, Expo config plugin), so treat the library pick as vendor advocacy; the deprecation and the capability checklist are the durable part. It stops at obtaining the credential — session/token handling is still yours (Keychain via RB-E-STORAGE, never AsyncStorage).
networking — Networking & HTTP client layer
react-native-nitro-fetch — architecture & benchmarks
You ship react-native-nitro-fetch — it swaps the fetch engine (Cronet/URLSession: HTTP/3+QUIC, Brotli, disk cache, prefetch, worklet parsing) behind the same API; benchmarks are vendor-run (~23% on their harness), so measure your own hot path.
The README doubles as the layer's best explainer: what actually backs fetch on each platform (Cronet vs URLSession), what HTTP/3+QUIC/Brotli/disk-cache buy you, prefetch-before-navigation, and worklet-side parsing — with their benchmark methodology. Read it to understand the layer even if you keep built-in fetch.
crossplatform — Sharing code across React (web) & React Native
use dom — incrementally migrating web UI to native with React
You ship react-native-web — it's in maintenance mode (2026); don't expand the bet. For incremental web-UI reuse inside native, Expo DOM Components (`use dom`) are the maintained migration path.
Deep-dive on Expo DOM Components and the `use dom` directive — run real web UI inside a native app and migrate to native views component-by-component; covers the Metro bundling, offline support, and honest WebView trade-offs. The primary source for the incremental-reuse path.
AI-Assisted React Native Migration for TV: Lessons From Zattoo
TV/cross-platform RN case study: share until a platform gives a reason to split, telemetry-driven perf, team reorg, and a deflated, realistic account of AI's role.
A concrete companion to this entry's share-by-layer thesis.
desktop — Desktop apps & web-to-native shells (packaging a React web app)
The Conductor Rewrite: what they changed to make it fast
You ship React in a Tauri shell — the Conductor postmortem's wins were structural (SQLite local-first, stable refs killing re-render cascades, virtualization), not memoization patches; fix root causes.
A React + Tauri desktop performance postmortem — SQLite local-first, TanStack Router structural sharing (stable refs killing re-render cascades), virtualization — fixing root causes instead of papering over with useMemo. Directly relevant to React-on-desktop.
A Technical Deep Dive Into the New Raycast
How Raycast ships one React + TypeScript codebase to both macOS and Windows via native shells (Swift/C#) plus WebKit — IPC design, memory breakdown, and concrete WebKit workarounds.
A durable model for cross-platform desktop on React without Electron.
UI — styling, components, animation, lists, a11y, i18n, charts
styling — Styling & theming
Why We're Breaking Up with CSS-in-JS
You ship runtime CSS-in-JS — per-render style serialization has a measured cost (~48% faster renders after dropping Emotion in this benchmark); compile-time styling (Tailwind/StyleX) moves that cost to build.
The canonical runtime-cost argument against runtime CSS-in-JS, from an Emotion maintainer: per-render style serialization is slow (a benchmark shows ~48% faster renders after dropping Emotion). Motivates the move to compile-time / zero-runtime styling.
StyleX: A Styling Library for CSS at Scale
You ship StyleX — its Babel compiler extracts deterministic atomic CSS at build time (no runtime injection), resolving specificity/shorthands at compile time so CSS size stays flat at scale.
Architecture explainer for the leading zero-runtime approach: a Babel compiler extracts styles into deterministic atomic CSS at build time (no runtime injection), resolving specificity/shorthands at compile time so CSS size stays flat at scale.
Moving Linear from styled-components to StyleX
You ship styled-components — Linear's production migration to StyleX is the playbook: build-time vs runtime styling, ~30% nav improvement, agent-driven codemods at 100k-line scale.
First-hand account of a large production CSS-in-JS to StyleX migration: build-time vs runtime styling, ~30% nav improvement, and agent-driven codemods at 100k-line scale. The migration companion to the runtime-cost argument above.
I've Maintained Linaria for Six Years: Here's Why I Built Something New
You ship Linaria — its maintainer says its foundational issues are unfixable by design; the library stays maintained but frozen, and his zero-runtime successor dx-styles (RSC-compatible) publishes a Linaria migration guide.
The Linaria maintainer's own verdict on the category: runtime CSS-in-JS is winding down, and two foundational Linaria issues can't be fixed without breaking its core design — so Linaria stays maintained but frozen (NOT deprecated), and his successor dx-styles (zero-runtime on wyw-in-js, RSC-compatible, typed recipe variants, token contracts) ships with a Linaria migration guide. Supersession-in-progress: watch dx-styles, no migrate rule yet.
The State of Zero-Runtime CSS-in-JS, Mid-2026
You ship zero-runtime CSS-in-JS — the field converged on plain class-name output, so pick on atomicity and design-system features: next-yak/Linaria for a styled-components codebase, vanilla-extract or Panda for typed styles, StyleX at hundreds-of-teams scale.
The comparative map this entry's options list lacks: where every live zero-runtime option actually sits — Linaria (maintained, frozen), next-yak (Rust compiler over styled-syntax, RSC-compatible), vanilla-extract (the TypeScript answer to CSS Modules, typed themes), Panda CSS (config-first, atomic output), StyleX (Meta's, strict constraints + deterministic merging), Griffel (Microsoft/Fluent UI, limited ecosystem interop), and dx-styles itself. Routes by situation rather than ranking: big styled-components codebase → next-yak or Linaria; typed styles with little setup → vanilla-extract or Panda; design system → dx-styles or vanilla-extract; hundreds of teams → StyleX; pragmatic → Tailwind or CSS Modules. The category has CONVERGED on plain class-name output, so the live differences are atomicity, authoring style and design-system features — not runtime cost, which the readings above already settle. KEPT ON THE 2026-08-04 ADVOCATE PASS after three cap-skips: recurring in three sources at once, and it is the only piece here covering the field rather than one library.
component-libs — Component & headless-UI libraries (web)
Building an LLM-safe design system
Argues a design system should become the only expressible decisions for LLM-authored code — token-only props, a polymorphic Box, StyleX compile-time enforcement.
A durable take on component libraries in the AI-coding era.
Building design components with action props using async React
A pattern for design-system components that accept action props and run them in internal transitions (useTransition/useOptimistic) for built-in pending/optimistic UI.
A durable component-API pattern for the async-React era.
animation — Animation & gestures
First-principles explainer on the real distinction (main-thread contention, compositor-friendly properties, WAAPI) rather than the CSS-is-always-faster myth.
A durable animation mental model that applies to web and RN reasoning alike.
How react-native-ease runs animations with no JavaScript loop
You ship react-native-ease — animations run entirely via Core Animation/ObjectAnimator with no per-frame JS or UI-thread worklet work; the mental model is iOS model vs presentation layers plus cross-platform spring physics.
Deep dive on driving animations entirely via Core Animation / ObjectAnimator with no per-frame JS, incl. iOS model vs presentation layers and cross-platform spring physics. The mental model for truly native-driven RN animation.
Chasing a Phantom Jump: making Skia + Reanimated smooth on low-end Android
You ship Skia — on low-end Android the dominant smoothness fix is SurfaceView over TextureView (no per-frame texture upload, ~50-65% less RenderThread CPU); smoothness is frame-cadence timing, not curve math.
A low-end-Android profiling deep-dive: smoothness is frame-cadence timing, not curve math; the dominant fix is SurfaceView over TextureView (no per-frame texture upload, ~50-65% less RenderThread CPU), plus stable-reference buffer mutation and quantizing per-frame values. With profiler-triangulation methodology (gfxinfo/Perfetto/Hermes).
The real cost of React Native animations: benchmarking every approach
You ship Reanimated — the only cross-library per-frame benchmark measured its shared values at ~36ms/frame at ~500 animating views; only the fully native-driven approach stayed under budget (vendor-run by the Ease author — re-measure).
The only cross-library per-frame benchmark: UI-thread cost of core Animated vs Reanimated (shared values AND the CSS API) vs Ease on real devices — at ~500 animating views only the fully native-driven approach stays under frame budget (Reanimated SVs measured ~36ms/frame). CAVEAT: the author created Ease, the approach that wins — treat the numbers as vendor-run and re-measure on your own screens; the methodology and the per-frame cost model are the durable part.
Which React Native Animation Library Should You Use for Performance?
You ship Reanimated — independently measured, it is the only library keeping continuous gesture input off the JS thread (2.9% vs Animated's 29% JS CPU while scrubbing), but its per-node UI-thread cost dominates when many nodes animate at once.
The INDEPENDENT replication the Expo/Ease benchmark above asks for — same three-way question (Animated with useNativeDriver, Reanimated 4.5, Ease 0.7), different author, reproducible harness (AndreiCalazans/react-native-animation-performance), Android release build on New Arch, 90Hz physical device, Maestro-driven, median of 3, 60 boxes animating. It splits the answer BY ANIMATION TYPE instead of picking a winner: for touch/state/loop all three keep JS at the idle floor and Ease drops the fewest frames with Animated close behind; SCRUB is the fork — Animated drives the value via PanResponder→setValue on the JS thread (29% JS CPU, ~26% of JS frames dropped, and useNativeDriver cannot save a value you set from JS each frame) while Reanimated keeps it entirely on the UI thread (2.9% JS CPU). Blunt version: Reanimated when a finger is dragging, Ease or the native driver otherwise. Two caveats the author states himself: 60 independent nodes deliberately punishes per-node cost (Reanimated's useAnimatedStyle mapper), so the UI-thread loop ranking is partly an artifact — at one hero element Reanimated is likely best overall; and the ~50MB memory premium it measured DISAPPEARS with Worklets Bundle Mode on (−~100MB PSS in the follow-up re-run).
A React trick to improve exit animations
Uses Suspense to freeze exiting content during animations; explains Fragment refs, useInsertionEffect, and Suspense DOM-update behavior.
A durable web exit-animation technique grounded in React internals.
Rewriting Rive React Native with Nitro Modules: up to 94× Faster Multi-View Loads
You ship Rive — the Nitro line (@rive-app/react-native, 0.4.x early) makes files/view-models shared typed objects: parse once, render many views (94× multi-view loads, ~4.7× lower memory in the authors' benchmark); the legacy unscoped package is quiet.
Why the Rive RN SDK's wins came from MODELING, not micro-optimization: the legacy module flattened files/view-models into a per-view God object, so every view re-parsed state; Nitro HybridObjects make them shared typed objects (parse once, render many) — 94× on a 24-view load, ~4.7× lower memory, ~0.3-0.4µs calls vs ~1.5µs TurboModule / ~21µs legacy bridge (iPhone 13 mini, release; the rewrite authors' own benchmark). A general lesson for native-module design: model objects, not modules.
lists — Lists & virtualization
How to Build the Fastest Apps: Break the Rules (App.js Conf 2026)
You ship Legend List — it mounts a fixed pool of absolutely-positioned containers once and signals individual containers to re-render at new positions, so scrolling never re-renders the list array (v3.0 stable covers RN + web; vendor talk).
Why Legend List is fast, from its author: it mounts a fixed pool of absolutely-positioned containers once and never re-renders that array again — instead it *signals* individual containers to re-render themselves at a new position/item as you scroll, and turns frequent size changes into animated-style updates rather than list re-renders. The generalizable lesson ('render once'): keep each render tiny by pushing it to the leaf that actually changed. Complements the peterp.me engine walkthrough with the same-source mechanism; announces v3.0 stable (RN + web). Vendor talk.
FlashList v2: a ground-up rewrite for React Native's New Architecture
You ship FlashList — v2 is New-Architecture-ONLY (old arch → pin v1.x), and the v2 rewrite changes the recycling machinery (progressive rendering, pre-paint correction).
The maintainer's architecture deep-dive on FlashList's New-Architecture rewrite — view recycling, progressive rendering, layout prediction, and pre-paint correction via synchronous measurement — explaining the recycling machinery from first principles, not just the API.
React windowing vs. component recycling
Cleanly separates the two long-list strategies — windowing (render only the viewport, mount/unmount on scroll) vs recycling (reuse nodes by reassigning keys) — and when to escalate.
Bridges web (react-window) and RN (FlashList).
What's actually happening inside Legend List
You ship Legend List — its tuning surface is the virtualization formula: estimated item size, draw distance, container-pool ratio, and asymmetric 1.5x/0.5x buffering.
Explains Legend List's virtualization formula — estimated item size, draw distance, container-pool ratio, asymmetric 1.5x/0.5x buffering. A concrete mental model for list recycling performance (complements the FlashList piece).
Virtual scrolling for billions of rows (techniques from HighTable)
You ship TanStack Table — for huge web tables (100k+ rows) HighTable's techniques apply: lazy slicing, the ~17M-px canvas-height ceiling with downscaled scrollbars, dual local/global scroll modes, decoupled axes.
The five techniques behind HighTable — lazy slicing, the ~17M-px canvas-height ceiling with downscaled scrollbars, dual local/global scroll modes, decoupled axes. The web huge-table counterpart to the RN list pieces above (HighTable is a listed option here).
Reactivity in TanStack Table V9
You ship TanStack Table — v9 (stable 2026-08-04) splits feature state into per-feature atoms behind a reactivity contract so cell re-renders no longer depend on whole-table state; the same subscription-grain lesson as the list readings here.
The architecture rationale behind the v9 line this entry's note records: v8 kept one stable table instance and let each adapter connect it to a framework's update model from the outside, which makes any state change look like whole-table churn. V9 puts a reactive graph underneath instead — per-feature atoms plus a `TableReactivityBindings` contract each adapter fills with its framework's own primitives — so a row selection updates that row and the counter, not every cell. The generalizable lesson matches this entry's Legend List readings: the cost of a big grid is what you make re-render, so put the subscription grain at the leaf.
a11y — Accessibility across web & native
Blocked aria-hidden: The Warning is Right, and Every Fix You've Found is Wrong
You hide regions when a modal or drawer closes — move focus OUT before the region becomes hidden or inert (not blur(), not setTimeout, not deleting aria-hidden), and prefer native <dialog>.showModal(), which handles the focus sequence for you.
One rule, and the reason the popular fixes are worse than the bug: FOCUS HAS TO LEAVE A REGION BEFORE THAT REGION BECOMES HIDDEN OR INERT. The browser's 'Blocked aria-hidden on an element because its descendant retained focus' warning is telling the truth — a screen-reader user's focus is about to land in a hole — and the three fixes that dominate search results (blur() the active element, wrap the close in setTimeout, or strip the aria-hidden attribute) all silence the console while leaving that user stranded. The fix is an ordering change in code most apps already have: move focus out first, then hide/inert the region, and inert the closing overlay itself (the step nearly everyone skips). The shortcut worth taking when you can: native <dialog> with .showModal() runs the whole focus dance for you — with the one case no browser can guess, restoring focus to an element that has since been removed from the DOM.
The Siren Song of ariaNotify()
You announce dynamic updates to screen readers — ariaNotify() (WAI-ARIA 1.3) is the coming replacement for aria-live hacks, but it's Firefox-only as of mid-2026 and invites alert()-style over-narration; keep semantic signals first.
The coming primitive for this entry's 'announce dynamic updates' facet: ariaNotify() (WAI-ARIA 1.3) pushes screen-reader announcements from JS — document.ariaNotify(str, {priority}) — replacing the hidden aria-live-region hacks whose timing/support failures the piece catalogs. Two durable caveats: it ships in Firefox ONLY as of mid-2026 (keep aria-live fallbacks), and it invites alert()-style overuse — narrating what existing semantics already convey interrupts screen-reader users who were navigating fine.
Accessibility in React: Common Mistakes and How to Fix Them
A durable React a11y reference from a recognized expert: semantic HTML, labeling, focus management on route/modal changes, ARIA live regions, with concrete useId/useRef patterns and a WCAG-cited checklist.
AI-Generated UI Is Inaccessible by Default
Why LLM-generated components ship empty accessibility trees, and a five-layer enforcement system (prompt constraints, jsx-a11y lint, axe-core runtime tests, CI gates, headless primitives).
Durable guidance as AI codegen becomes the default.
i18n — Internationalization (i18n)
Ahead-of-time compilation for next-intl
You ship next-intl — v4.8 precompiles ICU messages at build time into minified ASTs evaluated by a ~650-byte runtime, trading runtime message parsing for smaller bundles.
Why and how ICU messages are precompiled at build time into minified ASTs evaluated by a ~650-byte runtime, weighing function-based vs AST strategies against bundle size. Teaches the compile-time-vs-runtime and bundle-size tradeoffs from first principles.
ICU Message Syntax (core concepts)
You ship an ICU-based i18n layer (react-intl/next-intl/Lingui) — your message strings are ICU syntax (interpolation, plurals/selectordinal, select, number/date skeletons); ICU is a stable Unicode standard, so this reference doesn't go stale.
The canonical, example-driven explanation of the ICU message format — interpolation, plurals/selectordinal, select, number/date skeletons, rich text. ICU is a stable Unicode standard, so this foundational reference doesn't go stale.
charts — Charting & data visualization
You ship a D3+React chart stack — the durable division of labor is D3 for math/layout while React owns the DOM, composing low-level primitives instead of opinionated chart components (applies to visx, Recharts, any D3+React stack).
The architecture of web React charting — use D3 for math/layout while React owns the DOM, and compose low-level primitives instead of opinionated chart components. First-principles framing that applies to visx, Recharts, and any D3+React stack.
The Future of React Native Graphics: WebGPU, Skia, and Beyond
You ship Skia-backed RN charts (Victory Native XL or raw react-native-skia) — the rendering model underneath: JSI, immutable display lists, a unified WebGPU backend, and the canonical high-density line-chart-as-GPU-texture pattern.
How RN Skia renders graphics — incl. the canonical high-density line-chart-as-GPU-texture example, JSI, immutable display lists, a unified WebGPU backend. The rendering model under Victory Native XL and build-your-own Skia charts.
editors — Rich-text & content editors
The Unreasonable Effectiveness of the ProseMirror Model in Rich Text Transformation
You ship a ProseMirror-family editor (TipTap/BlockNote/ProseMirror) — nodes, marks, positions, and mappings are the document model under your editor; this teaches them through a real parse→transform→serialize pipeline.
Teaches ProseMirror's core abstractions (nodes, marks, positions, mappings) through a real parse→transform→serialize pipeline. Durable conceptual grounding for the document model under most React editors.
svg — SVG, vector graphics & icons (React Native)
Introduces Redraw — 2D primitives on WebGPU where shaders are TypeScript functions that receive geometry (tangent, arc length) to compute stroke width / feathering / material per-point, enabling physically-based 2D rendering.
The Skia author's bet on WebGPU as the unified graphics runtime; experimental, but the direction RN GPU graphics is heading.
How to import SVG files in React Native using react-native-svg
You ship react-native-svg — the canonical workflow how-to: inline SVG, importing designer .svg files as components via react-native-svg-transformer, SvgUri/SvgXml, and animating SVGs.
Practical deep-dive on inline SVG, importing .svg as components via react-native-svg-transformer, SvgUri/SvgXml, and animating SVGs — the canonical how-to for the react-native-svg workflow.
maps — Maps & geolocation UI
react-native-maps vs Mapbox RN vs MapLibre RN (2026)
You ship an RN map library — the decision table: Google ~$7/1k mobile loads vs Mapbox $0.50/1k after free tier vs MapLibre free-but-BYO-tiles; only Mapbox/MapLibre expose offline region-download APIs (react-native-maps does not).
The concrete three-way comparison behind this entry's axes: per-load pricing math (Google ~$7/1k mobile loads vs Mapbox $0.50/1k after free tier vs MapLibre free-but-BYO-tiles), which libraries actually expose offline region-download APIs (Mapbox/MapLibre yes, react-native-maps no), GL style customization, API-key requirements, and New-Architecture status — with code for each. Team-authored (no individual byline) but sourced and measured; use for the decision table, not authority.
calendars — Calendars, date pickers & event grids
Super Calendar — docs (views, gestures & architecture)
You ship Super Calendar — the native renderer requires Reanimated 4 + Gesture Handler + Legend List; views are virtualized and snap-paged (month/week/day/3-day/schedule), and @super-calendar/dom renders the same core on web.
The reference for the new event-grid approach: a platform-free core with native (Reanimated 4 + Gesture Handler + Legend List) and DOM renderers, virtualized snap-paged views (month/week/day/3-day/schedule), and gesture semantics (pinch-to-zoom time grid, long-press drag, grip resize, drag-empty-space-to-create). Documents the stack a modern RN event grid actually requires — useful even if you pick something else.
sheets — Bottom sheets & modal sheets (React Native)
You ship a bottom sheet — velocity-based dismissal, snap logic, and scroll-vs-drag handoff are design decisions, not library defaults; this is the canonical rationale to configure them against.
The design rationale under good sheets/drawers, from the author of web's canonical drawer (Vaul): velocity-based dismissal over distance thresholds, snap-point logic, scroll-vs-drag handoff, and background scaling — the interaction details that decide whether a sheet feels native. Web-authored, but it is the why-good-sheets-feel-good reference, exactly as this corpus uses his toast piece in RB-E-POLISH.
polish — UX polish primitives — toasts, haptics, splash screens, image viewers (React Native)
You ship sonner-native — the design rationale it imports: interruptible transitions over keyframes, index-scaled stacking, pause-on-hidden, momentum swiping, gap-filling hover pseudo-elements.
The design rationale under sonner (and thus sonner-native): interruptible transitions over keyframes, index-scaled stacking, pause-on-hidden, momentum swiping, gap-filling hover pseudo-elements. Web-authored, but it is the canonical 'why good toasts feel good' — the taste this entry's toast pick imports.
Platform & native (RN)
native — Native modules & the New Architecture
How to Make Pure JSI Code Faster in React Native (Part 1)
You ship Nitro Modules — the runtime mechanics it compiles down to: HostFunction vs HostObject, the Object+NativeState pattern, stack vs heap, and minimizing JS-to-native crossings, with reproducible Hermes benchmarks.
How JSI bindings actually work at the C++/Hermes boundary — HostFunction vs HostObject, the Object+NativeState pattern Nitro compiles down to, stack vs heap, minimizing JS-to-native crossings — with reproducible Hermes benchmarks. The runtime mechanics under Turbo/Nitro Modules.
Making JSI Faster with More Efficient Data Structures (Part 2)
You ship Nitro Modules — data representation across the JSI boundary (array-of-objects vs flat array vs ArrayBuffer, numeric vs string contracts) can swing performance up to ~30x with no algorithmic change.
How data representation across the JSI boundary (array-of-objects vs flat array vs ArrayBuffer, numeric vs string contracts) can swing performance up to ~30x with no algorithmic change. First-principles guidance for New-Architecture native modules.
How Margelo Helped Discord Improve React Native's New Architecture Performance
You ship Reanimated on the New Architecture — the canonical Fabric jank postmortem: cloneShadowTreeWithNewProps over-cloning the shadow tree plus redundant layout passes for non-layout props, with fixes upstreamed.
Low-level New-Architecture jank postmortem: Reanimated's cloneShadowTreeWithNewProps over-cloning the Fabric shadow tree plus redundant layout passes for non-layout props, with fixes upstreamed. Canonical Fabric / New-Arch internals.
Four Years of React Native Quick Crypto: From Wallets to Node Parity
A four-year native-library architecture case study: wrapping OpenSSL for Node behavior-parity, a sync-first threading model with async escape hatches, the hand-written-JSI to Nitro codegen migration, and security audit as architecture validation.
Generalizable lessons for native-module authors.
The Memory Hermes Can't See: Stale Shadow Nodes in React Native
You debug memory on the New Architecture — Hermes heap snapshots cannot see retained Fabric ShadowNodes (C++ memory pinned by JS wrappers), so a flat JS heap with growing process memory means profile the native side too.
The memory-leak sibling of the Discord jank postmortem above: Fabric ShadowNodes are C++ objects retained via JS wrapper objects, so unmounted views' wrappers can pin whole shadow-tree revisions (amplified by Reanimated's per-frame revision cloning) — and none of it appears in Hermes heap snapshots, because the retained memory sits outside the JS heap. The author's two candidate mitigations (periodic forced GC; per-wrapper setExternalMemoryPressure) are both judged not production-ready — this is debugging awareness, not a shipped fix. (2026-08-05)
media — Camera, video & real-time media (WebRTC, frame processing, filters)
Building a video call app with filters
You ship WebRTC calling (LiveKit / react-native-webrtc) — don't fork the stack for filters: segment off the hot path, GPU-composite, and inject processed VisionCamera frames into the existing VideoSource; mind YUV conversion and monotonic timestamps.
Architecture deep-dive: real-time RN video-call filters (background blur, virtual backgrounds, Center Stage auto-zoom, live drawing) by injecting processed VisionCamera frames into LiveKit's WebRTC VideoSource without touching encoder/transport/signaling. Covers off-thread segmentation (MediaPipe/Vision), Metal/Skia compositing, YUV↔I420/NV12 conversion, and the monotonic-timestamp + buffer-pooling gotchas.
MoQKit: a native mobile SDK for MoQ on iOS and Android
Architectural intro to Media over QUIC for mobile — the session/namespace/track model, why moq-lite over moq-transport, and where it sits between WebRTC and HLS.
A durable real-time-media transport reference.
What's New in VisionCamera V5?
You ship VisionCamera — v5 is a full Nitro rewrite (Constraints API replaces Formats, ~15x lower call latency) but still stabilizing: adopt pinned-patch with a device-matrix pass; don't linger on frozen v4.
The canonical v5 reference for this entry's default camera pick: the full Nitro rewrite (−3k LOC of hand-written JSI, ~15x lower call latency vs Turbo Modules), the Constraints API replacing Formats, in-memory photo capture, depth/RAW/multi-cam, and modular frame-processor plugins. Read before betting real-time work on v5.
Scanning Barcodes in React Native Apps: The Complete Guide (2026)
You scan barcodes in React Native — pick by the native engine underneath (ML Kit / AVFoundation / VisionKit / ZXing): decoder quirks belong to the engine, not the wrapper. Need one code and no custom UI? A platform scanner call beats mounting a camera view.
The cross-library selection guide the VisionCamera-scoped piece below doesn't cover, and its durable core is the ENGINE MAP: every RN scanning library wraps one of four native engines — Google ML Kit (VisionCamera's Barcode Scanner on both platforms, expo-camera on Android, data-scanner on Android), AVFoundation's AVCaptureMetadataOutput (VisionCamera's Object Output, expo-camera on iOS for most formats), VisionKit's DataScannerViewController (react-native-data-scanner on iOS 16+, expo-camera's launchScanner), and ZXing (which expo-camera bundles on iOS to decode PDF417/Code 39/Codabar). The consequence is the useful part: decoder quirks belong to the ENGINE, not the wrapper, so if ML Kit mis-reads an inverted barcode every ML-Kit-based library does, and iOS reporting UPC-A as EAN-13 shows up in everything built on Apple's APIs. The routing: one code and no custom UI → react-native-data-scanner (one call, no camera view to build); in-app camera with overlays or validation → VisionCamera + the barcode plugin; smallest iOS-only footprint → VisionCamera's Object Output; Expo Go → expo-camera; damaged/dense codes at industrial scale → a commercial SDK. Author bias is explicit (he wrote VisionCamera and data-scanner), and the post corrects a vendor claim that VisionCamera uses VisionKit — it never has. Note react-native-data-scanner is 0.1.2 on npm (verified 2026-08-18): the routing advice is sound, the package is early.
QR and Barcode Scanning in React Native with VisionCamera V5
You ship VisionCamera and scan codes — three APIs (CodeScanner / useBarcodeScannerOutput / frame processors); narrow barcodeFormats and outputResolution for latency, and mind the frame-vs-preview coordinate gotcha.
By VisionCamera's creator: three scanning APIs (CodeScanner / useBarcodeScannerOutput / frame processors), narrowing barcodeFormats and outputResolution for latency, the frame-vs-preview coordinate gotcha, and MLKit vs Apple's native AVCaptureMetadataOutput vs commercial SDKs. The reference for RN code scanning.
storage — On-device storage & persistence
SQLite for React Native, but 5x faster and 5x less memory
The library author walks the JSI/C++ internals that make op-sqlite fast and memory-light — lazy HostObject conversion, std::variant over a custom struct, key-sharing across result rows — with benchmarks.
The mechanics of high-performance JSI SQLite, not API usage.
An Interactive Guide to TanStack DB
Builds the local-first reactive-persistence mental model from first principles — Collections, live queries via differential dataflow, optimistic transactional mutations — contrasting it with request/response fetching.
The shift to sync-engine thinking.
Why We Did Not Move MMKV Writes to a Worklet: The Serialization Cost
You ship MMKV with worklets — moving writes into a worklet does not offload them: serialization at the boundary cost the same ~29.56ms as the write, and passing a whole store object cost ~132ms. Measure the boundary cost before moving work off the JS thread.
A measured NEGATIVE result, which is why it is worth holding: MMKV writes are synchronous and block the JS thread, so moving them into a worklet looks like free relief. It isn't. Moving just the write left the ~29.56ms cost intact — it simply moved from the write into createSerializableString, because copying the string into the worklet costs what the write did. Sending the raw store object instead was worse (~132ms, cloning every property one at a time via cloneObjectProperties/clonePlainJSObject), and Bundle Mode changed nothing (~136ms), confirming the cost tracks data-structure size rather than compilation. The durable rule: a worklet is not a free way to move work off the JS thread — you pay serialization at the boundary, so measure that cost first and send the smallest payload you can.
native-ui — Native UI extensions — Live Activities, widgets, App Clips, portals
Apple Home Screen Widgets with Expo (Continuous Native Generation)
Generating native Apple widget targets from Expo via CNG — pbxproj manipulation to keep SwiftUI targets editable yet outside /ios, App Group / NSUserDefaults data sharing, CSS-to-colorset conversion.
The foundational mechanism behind Expo Targets / expo-widgets.
Using Live Activities in a React Native App
End-to-end Live Activities in RN — the ActivityKit Attributes/ContentState model, a separate widget-extension target for Lock Screen + Dynamic Island, a native module bridging JS↔Swift, and the HTTP-refresh vs APNs-push tradeoff.
Platform constraints that outlast any single library.
How we built the v0 iOS app (React Native + Expo)
Production case study of making RN feel truly native on iOS: Liquid Glass via @callstack/liquid-glass, native menus via Zeego/UIMenu, patching RCTUITextView for platform-correct text behavior, ~1,000 lines of keyboard logic on react-native-keyboard-controller (see RB-E-KEYBOARD), synchronous New-Arch measurements, LegendList — and the share-types-and-logic-not-UI lesson.
What 'native feel' actually costs and where the wins come from.
keyboard — Keyboard handling & avoidance (React Native)
The Go-To Guide for Understanding Keyboards in React Native (Part 1)
You ship no keyboard library — core KeyboardAvoidingView snaps on Android (no per-frame insets) and breaks under Android-15 edge-to-edge; react-native-keyboard-controller is the modern parity fix.
Why keyboards behave differently per platform — iOS scheduled animation vs Android per-frame WindowInsetsAnimationCallback insets, why core KeyboardAvoidingView snaps on Android, Android-15 edge-to-edge breakage, and when to reach for KeyboardAvoidingView / KeyboardAwareScrollView / KeyboardStickyView.
payments — In-app purchases & payments
Cross-platform subscription state: sharing entitlements between Android and iOS
Why unifying subscription entitlements across iOS/Android is hard — Apple signed-JWS vs Google purchase-token REST, HTTPS notifications vs Cloud Pub/Sub, subscription groups vs base plans/offers — and the four-part DIY architecture.
The root reason IAP libraries/services exist.
Building the RC Fortress: protecting payments against outages
A resilience case study for keeping purchases working when subscription backends fail — cached paywall snapshots, temporary offline entitlements, buffered request log/replay — with tradeoffs made explicit.
The realities of subscription infra regardless of library.
brownfield — Brownfield integration & micro-frontends
Migration to React Native in 2026 Starts With a Delivery Question
You are weighing a native→React Native migration — pick by where the risk can sit: brownfield preserves installed-app continuity but you own a runtime boundary; greenfield is cleaner but must reproduce auth, deep links and push identity before cutover.
The decision that comes BEFORE this entry's tooling: brownfield or greenfield. The framing is that the trigger for migrating is usually delivery cost (two implementation tracks, two review paths, two QA cycles, two release trains), and that the choice between paths is really a choice of where the risk sits during the transition. Brownfield keeps the native apps as the production host and moves one flow at a time — it preserves installed-app continuity (session state, secure storage, push identity, subscriptions, app extensions) and leaves a native fallback, at the cost of owning a runtime boundary (packaging, host integration, native↔RN navigation, shared state) while maintaining two surfaces at once. Greenfield builds a replacement and ships it under the same bundle ID — less architectural drag and a codebase agents work better in, but continuity becomes the risk: auth, deep links, push tokens, app groups, persisted data and analytics all have to survive the cutover, and mature products fail on accumulated behavior rather than on screens. The third option is the useful one: start greenfield with a fixed checkpoint and a REAL brownfield fallback, where the checkpoint tests product continuity (authenticated flows, analytics, accessibility, performance, at least one meaningful native boundary) and not just how fast screens get rebuilt.
Rebuilding the Doctolib Homepage from Webview to Native
Production case study migrating a 115M-hits/month homepage from WebView to native RN with a BFF-driven section architecture (~50% TTI improvement, measurable conversion gains).
Durable brownfield-integration lessons.
Unlocking Expo Updates in an Isolated Brownfield Architecture with SDK 55
The capability-flip walkthrough behind this entry's note: running EAS/Expo Updates inside an isolated brownfield embed (XCFramework packaging via `npx brownfield package:ios`), which had been a hard limitation of embedded-RN architectures.
Read when you need OTA on brownfield screens.
React Native production lessons from React Universe Meetup x Zalando
Four hard-won production patterns — brownfield-handoff metrics (Meaningful Render), video-feed jank sequencing, native API bridging, on-device LLM hardware variance.
Real-world scale-stage RN guidance.
games — Games, 3D & AR/VR — interactive / real-time rendering
React Native Skia — For Us, For You, and For Fun
The foundational architecture of react-native-skia: JSI for direct C++/JS communication, a custom React reconciler powering the declarative API, and Reanimated-driven animation.
The enduring design under RN's 2D GPU drawing — the base for RN games and interactive visuals.
alt-frameworks — Alternatives to React Native (cross-platform frameworks)
We Built the Same App in KMP and React Native — Here's What We Found
The controlled comparison this entry needed: identical unoptimized apps on 6 devices measuring size/startup/RAM/CPU/frames.
KMP wins Android decisively (8x smaller, 2-4x startup, ~50% less RAM — no JS runtime); iOS converges, with RN using 3-4x LESS memory (UIKit rendering vs KMP's resident Skia). Credible precisely because an RN consultancy published the unflattering Android numbers; ends on the right frame — performance is one input, DX and ecosystem are others.
Under the hood of MDN's new frontend
Architecture case study replacing a React SPA with server-side templating + Lit web components (per-component CSS, Declarative Shadow DOM, Rspack).
An authoritative counter-perspective on when NOT to ship a React SPA.
From React to native web with nanotags: a migration that saved 100 KB
When a marketing/content site doesn't need React — migrating to Web Components (Custom Elements + Astro + nanostores, ~3KB vs ~63KB), with the boilerplate/accessibility trade-offs nanotags addresses.
Durable do-you-even-need-React reasoning.
Upgrading Checkout Blocks app to Polaris web components
You ship React inside a byte-budgeted embed (checkout widget, third-party extension) — react-reconciler alone is ~89KB, so swapping to Preact via @preact/compat is usually the largest single cut available.
The PREACT data point the other do-you-need-React readings lack, and the rare case where a hard number forces the decision: Shopify's Checkout Blocks extensions (rendered on a third of all customized checkouts) had to fit a 64KB gzip per-bundle limit enforced by the 2026-01 remote-dom CLI, and were at 300–356KB raw / ~100–112KB gzipped. Dropping react-reconciler by moving React→Preact was the single biggest win at ~89KB and got them most of the way to budget; replacing liquidjs (~73KB) with an in-house parser and dayjs with a scoped date utility closed the rest, while markdown-to-jsx was kept by aliasing onto @preact/compat. Transferred bundle sizes fell 40–85% across the five extensions. Also a credible AI-assisted-migration pattern: an in-house agent skill did the mechanical React→Preact and component swaps against a parity test suite built from thousands of real merchant configurations, with engineers on the judgment calls.
How We Rewrote 130K Lines from React to Svelte in Two Weeks
A migration case study contrasting React's virtual-DOM overhead with Svelte's compiled reactivity for an AI-driven browser UI, including the LLM-migration ruleset that kept the Svelte idiomatic.
A concrete framework-tradeoff data point for teams weighing leaving React.
Build, test, observe, secure
build — Build tooling, bundlers & monorepo
How Teamworks Cut Mobile Release Time to 10 Minutes
You ship Re.Pack — the Teamworks case is the reference architecture: mini-apps on Module Federation behind a shell app with separate host/mini-app CI lanes took change lead time from days to ~10 minutes.
The production receipt for the Re.Pack/Module-Federation lane: Teamworks' seven mini-apps moved off Metro onto Re.Pack + Module Federation with a shell app and two CI/CD lanes (host vs mini-app), cutting change lead time from 1-2 days to ~10 minutes with multiple staging deploys per day. Vendor case study (Callstack builds Re.Pack) — but the numbers are client receipts, and it grounds this entry's own when-clause: module federation is worth the complexity when independent teams need independent release cadences in one app.
Things I Learned While Building Expo
The philosophical background behind this entry's Expo-vs-bare row, from the person who built much of it: dogfooding as the design tool, users articulating symptoms not solutions ('a runtime that was theirs, not ours' → dynamic runtime generation / prebuild), trust compounding through the expo-eject criticism years, and telemetry settling architecture debates.
Durable platform-building judgment, found by the 2026-07-16 back-audit of TWiR #284.
The first-principles explainer for WHY the JS toolchain is going Rust — memory safety, no GC, real parallelism, the redundant-parsing problem — mapping the whole landscape (esbuild, SWC, Oxc/Biome, Rspack, Rolldown).
Durable cross-cutting context, not a single release.
You ship Vite — v8 unifies dev and prod on Rolldown (one Rust bundler, 10-30x faster) instead of the unsustainable esbuild+Rollup pair, with Oxc semantic analysis driving better tree-shaking.
Why maintaining two pipelines (esbuild + Rollup) was unsustainable and how Rolldown unifies dev/prod on one Rust bundler (10-30x faster), with Oxc semantic analysis driving better tree-shaking. The primary source for the Vite+Rolldown+Oxc consolidation.
Exploring Inlined Requires: how they really work
You bundle with Metro — inlineRequires mechanics: why React/RN stay hoisted, why default imports aren't inlined, and how rnx-kit's esbuild path differs (real tree-shaking vs startup-only).
Exactly what Metro's inlineRequires Babel transform does, why React/RN stay hoisted, why default imports aren't inlined, and how rnx-kit's esbuild path differs (real tree-shaking vs startup-only). The canonical Metro startup-mechanics reference.
The Complete Guide to React Native Build Optimization
Why RN Android builds are slow (conservative Gradle/Metro/C++ defaults) and how parallel Gradle, dynamic Metro workers, ccache, and single-architecture builds cut times from 20+ min to 2-5 min, with benchmarks.
The RN-CI build-perf dimension the other readings here don't cover.
testing — Testing strategy & tooling
How we raised mobile end-to-end test stability to 98%
You run native E2E and fight flakiness — most of it lives in the API, not the tests: force an assertion on every step, find elements visually instead of by test ID, name escape hatches UNSAFE_, and gate new tests on repeated runs (Shopify: 50% → 98%).
The production evidence behind 'flaky native E2E is a framework problem, not a test problem'. Shopify's largest mobile app ran Appium via WebdriverIO with React Native test IDs since 2023 and had to pull the suite OUT of blocking CI; the rebuild put it back at 98% stability (individual test successes / total runs, up from 50%). Two changes did it. First, a builder-style API that makes flaky tests hard to write: every step carries an assertion (validated both ways — false before the action, true after), reusable named step sequences, and escape hatches deliberately named UNSAFE_ (UNSAFE_timeoutInSeconds, UNSAFE_testID) so they show up in review. Second, elements are found the way a user finds them — each step screenshots and matches visually, PaddleOCR for text and OpenCV for icons (grayscale, color-inverted variants, multiple sizes, adjacency rules to disambiguate duplicates) against Polaris design-system SVGs — which also removes the inspector round-trip from authoring and is why agents write correct tests on the first try. Plus a pre-promotion flakiness gate: a new test runs many times and is rejected above a failure threshold. Residual failures are network flakes and simulators failing to boot.
You ship Testing Library — query by role/label, not data-testid: accessible queries are both the stronger test and a free a11y audit; testid queries silently hide inaccessible markup.
The bridge between this entry and RB-E-A11Y: querying by data-testid silently hides inaccessible markup, while role/label queries fail exactly when a real assistive-tech user would — so accessible queries are both the better test AND a free a11y audit. Sharpens the Testing-Library philosophy the two Dodds pieces establish.
Write tests. Not too many. Mostly integration.
You have a test runner — spend it on integration tests over mock-heavy unit suites: confidence per effort is the metric, not coverage.
The foundational testing-strategy essay: maximize confidence per effort by favoring integration tests over mock-heavy unit suites and coverage-chasing. The origin of the Testing-Trophy mindset.
Testing Implementation Details
Why tests coupled to internals are brittle (false failures on refactor, false passes on breakage) and why to test behavior the way users use it.
The mental model behind Testing Library.
dx — Developer experience — CI, lint/format, hooks, monorepo, onboarding
Best CI/CD for mobile apps in 2026: a practical comparison
The only structured selection matrix for mobile CI platforms (EAS Workflows vs Bitrise vs Codemagic vs GitHub Actions): fingerprint-based repack turning 10–15min builds into ~2min JS-only builds, and GHA macOS runners measured ~2.4x slower than Codemagic M4s.
READ AS A VENDOR DOC — Expo wins its own comparison; the evaluation axes (runner hardware, cache strategy, fingerprint/repack) are the durable part.
Expo without EAS: scaling the React Native DX of an app with 90M+ users
You ship Expo at scale — Doctolib's blueprint runs the bare workflow without EAS: fingerprint caching + JS patching halved CI builds while contributors grew 9→105.
Large-scale case study adopting Expo's bare workflow (not EAS) with fingerprint caching + JS patching to halve CI builds and grow contributors 9→105. A durable enterprise RN build/CI-DX blueprint.
observability — Crash reporting, monitoring & observability
Bringing Lighthouse to the App: Core Web Vitals for React Native
You run RN in production — crash reporting alone isn't performance observability: Indeed's blueprint adapts Core Web Vitals (TTFF/TTI/FID) into an RN perf hook with composite scoring.
Adapts web Core Web Vitals (TTFF/TTI/FID) into a React Native performance hook with composite scoring, from a real ViewJob rollout. A durable blueprint for measuring (not just crash-reporting) RN performance in production.
The Hidden Cost of Hydration Mismatches
You server-render — one hydration mismatch makes React recreate the DOM and re-trigger LCP at hydration time; mismatches are a measurable LCP tax, not a cosmetic console warning.
Web-side production-perf diagnosis from real consulting: a single hydration mismatch makes React recreate the DOM, and because LCP only tracks NEW elements, the remounted (font-swapped, larger) text re-triggers LCP at hydration time — green→red with no obvious cause. Durable lessons: keep server/client renders identical, scope unavoidable mismatches with Suspense, and know how the metric itself measures (the metric mechanics are the observability half — the rendering-strategy background lives in RB-E-META-FRAMEWORKS's readings). The web counterpart to the Indeed RN piece above.
security — App security — device trust, secrets, dependency risk
An RCE postmortem on CVE-2025-55182 in React's Flight protocol (thenable abuse, prototype-chain exploitation), with durable lessons on runtime-vs-build-time type safety and lenient-parsing attack surface.
Canonical RSC security case study.
The Flight Protocol Made Your DoS My Problem
A DoS deep-dive (CVE-2026-23870) in the RSC Flight deserializer, with the generalizable lesson that dissolving a network boundary into developer ergonomics still owes a threat model (applies to tRPC/GraphQL/WebSockets too).
Shai-Hulud Postmortem (npm supply-chain worm)
You run a production pipeline — supply-chain is the real React-ecosystem risk: disable npm install scripts, use OIDC publishing, and layer defenses (the Shai-Hulud mitigations apply to every delivery pipeline).
A first-party postmortem of the Shai-Hulud worm (preinstall-script credential exfiltration) with concrete mitigations — disable npm install scripts, pnpm 10, OIDC publishing. The supply-chain reading this entry's own note calls for; applies to any React/RN delivery pipeline.
Postmortem: TanStack npm supply-chain compromise
First-party postmortem of the incident this entry's note cites: 84 versions across 42 @tanstack/* packages, via a pull_request_target 'Pwn Request' → pnpm store-cache poisoning → OIDC token extraction from the runner.
The CI/CD-side attack chain — a different door than the install-script family covered by the Shai-Hulud and NodeSource readings.
RSC Server Functions Are Not An API Boundary
You ship an RSC framework — server functions are reachable via direct POST regardless of UI: auth/authz must live INSIDE every server function, and deploy skew breaks old clients.
The architectural half of this entry's RSC stance: compiler-generated server references are reachable via direct POST, so auth/authz must live INSIDE every server function — plus the rolling-deploy skew failure mode (generated function IDs drift across deploys and break old clients). Treat stable server functions as formal API boundaries. (Site is a JS shell; content verified via its RSS feed.)
Weaponizing and Defending the React Flight Protocol: Deserialization Sinks in RSCs
You ship RSC — the Flight payload is a deserialization sink, not inert data: validate everything crossing the boundary with a strict schema and harden CSRF on server functions.
The DEFENSE half of this entry's Flight-protocol readings, which are otherwise all attack postmortems. Walks the protocol as an attack surface — a line-delimited format with its own type system, its own reference resolution, and its own rules for reconstructing executable behavior on the client — then works through the CVSS 10.0 React2Shell mechanics (CVE-2025-55182) to a RANKED set of defenses, from strict schema validation of everything crossing the boundary to CSRF hardening. Read when you ship RSC and need practice, not just incident history.
Disrupting supply chain attacks on npm and GitHub Actions
You run a production pipeline — GitHub's 2026 platform defaults (staged publishing, install-script blocking, Dependabot cooldown, account lockdown) now cover several supply-chain layers; know which mitigations remain yours (egress control, non-npm registries).
The first-party umbrella over this entry's whole supply-chain thread: GitHub's 2026 program in one post — npm staged publishing, install-script restrictions (npm v12), 72-hour read-only account lock after email/2FA-recovery changes, Actions hardening (checkout defaults, workflow-execution policies, read-only cache), an outbound-network-firewall technical preview, and a 3-day default Dependabot cooldown. The platform-side complement to the Shai-Hulud and TanStack postmortems' local mitigations.
Blocking Install Scripts Is Not a Silver Bullet
The nuance behind this entry's supply-chain note: npm v12's default block on preinstall/install/postinstall closes the INSTALL-TIME door but leaves the EXECUTION-TIME door open.
Attackers already moved the payload into the module body as a top-level side effect (runs on first require), or ship a binding.gyp so npm's implicit node-gyp rebuild fires anyway (the June-2026 Miasma campaign). Removing a trigger isn't removing the capability — so layer defenses: Node's --permission model (--allow-net / --allow-child-process / --allow-fs-write to cap what running code may DO), CI egress allow-listing (Harden-Runner), and container/seccomp isolation. Install-script blocking raises the floor; it is not the ceiling.
ota — Over-the-air (OTA) JS updates & release channels (React Native)
The production playbook for OTA updates
You ship OTA updates — run them like releases: staged percentage rollouts, a monitored bake period, and know abort vs republish-rollback as distinct mitigations before you need one.
The operational canon for this entry: staged percentage rollouts as exposure control, what to monitor while an update bakes, and aborts vs republish-rollbacks as distinct mitigations — 'sometimes it helps to go a little slower.' Vendor-authored but the staged-rollout discipline is platform-agnostic. (Body verified via the page's embedded content JSON — the blog is a JS shell.)
EAS Update introduction (docs)
The reference for the hosted-default choice: how updates map to channels, phased rollouts to a percentage of users, and rollback-by-republish ('much like a new commit').
Read before designing a release-channel scheme.
AI in React apps
ondevice-ai — On-device AI / ML
Fitting RAG in Your Pocket: Local Retrieval in React Native
You are building on-device RAG in React Native — memory binds before quality: generator + embedder must fit together (~900MB on a budget phone; a 1.07GB model dies on an untrappable native OOM) and query and documents need one embedding model.
The build behind this entry's react-native-rag / local-RAG option rows, done by hand so every constraint is visible: a WhatsApp export chunked, embedded and searched entirely on a $100 Android phone in airplane mode. The stack is one engine and one store — @react-native-ai/llama (llama.cpp) runs BOTH the embedder and the generator, and react-native-nitro-sqlite statically links sqlite-vec so KNN is a vec0 virtual table queried with `WHERE embedding MATCH ? AND k = ?`, no second ML runtime and nothing fetched at runtime. What makes it durable is the failure list. MEMORY IS THE CEILING, not accuracy: ~900MB usable RAM holds Qwen2.5-0.5B-Instruct Q4 (469MB) beside the 119MB embedder, and Qwen2.5-1.5B (1.07GB) hard-crashed the process with an uncatchable native OOM that JS cannot trap. The context window is paid for in KV-cache RAM, so it is capped at 4,096 tokens and a 21,000-token export is REJECTED outright ('Context is full'), not truncated — which is the whole reason retrieval exists here. Query and documents must be embedded by the same model with the same normalization, or search returns noise (the author calls this the number-one RAG pitfall). The multilingual embedder (paraphrase-multilingual-MiniLM-L12-v2, 384 dims, ~119MB at Q4) is worth its size the moment chats aren't pure English — all-MiniLM-L6 collapsed non-English messages to nearly identical vectors. Chunk boundaries are part of the data model: strip the speaker or timestamp and the model hallucinates them back. And a small model needs an explicit 'say you don't know' escape plus replayed recent turns, or follow-up questions retrieve the wrong thing entirely.
On-Device AI Beats Cloud for TTS — Here's Why
You ship react-native-executorch — the on-device-vs-cloud TTS case (Kokoro): cost, latency and privacy favor on-device, with the tradeoffs being voice/language coverage and a custom C++ phonemizer.
A reasoned cost/latency/privacy case for on-device TTS (Kokoro via react-native-executorch), with the economics and the tradeoffs (voice/language coverage, a custom C++ phonemizer). A durable framing for the on-device-vs-cloud decision.
Edge AI in Production: What Apple, Meta, and Google Already Ship On-Device
You're weighing on-device AI in React Native — it's production-proven at big-tech scale (Meta runs ExecuTorch inside WhatsApp/Instagram/Messenger), and small models get good enough through task-specific fine-tuning, not size.
Survey evidence that on-device AI is production-proven, not experimental: Apple ships multimodal-embedding photo search + hybrid Siri; Meta runs ExecuTorch in WhatsApp (network prediction), Instagram (SqueezeSAM cutouts) and Messenger (transcription); Google ships scam detection + Gemini Nano; Snapchat runs 10MB AR models. Ends in RN ExecuTorch pointers (Gemma/Qwen, ~30MB quantized Whisper Tiny STT) — vendor self-promotion, they author the lib. The durable framing: 'fine-tuning is what makes a small model good enough.'
Building a Real-Time Face Recognition App in React Native with VisionCamera
You ship VisionCamera and want on-device inference — frame processors hand you each frame synchronously on a native thread, with no serialization or pixel copy; that is what makes a real-time pipeline viable (~39ms per cycle on a Galaxy S21 Ultra).
The end-to-end build this entry's option rows only imply: a fully on-device recognition pipeline — detection → tracking → alignment → embedding → matching → liveness — on VisionCamera 5 frame processors, with ONNX Runtime (CPU/XNNPACK) for inference and Reanimated shared values bridging worklet and JS. Two things make it durable knowledge rather than a tutorial. First, the architectural reason it can work at all: the frame processor gets each YUV frame synchronously on a dedicated native thread as a worklet, with no bridge serialization and no pixel copy into JS. Second, real numbers on a Galaxy S21 Ultra — YuNet detection (~230KB model) 3–6ms/frame at 128×128, SFace embedding (37MB, 19MB int8) ~29ms, ~39ms end-to-end per detection cycle, gallery matching in microseconds for 512 entries — plus the budget trick of running detection every 10th frame and letting tracking bridge the gaps. Uses ONNX Runtime rather than this entry's ExecuTorch default, which is itself a useful data point.
ai-ui — Generative UI & in-app AI
Generative User Interfaces — rendering UI with language models
You ship the Vercel AI SDK — the generative-UI model: tools return structured JSON mapped to React component props; the client-side switch statement doesn't scale, so stream components during generation via createStreamableUI/RSC.
The core generative-UI mental model: tools return structured JSON that maps to React component props; the client-side switch-statement scaling problem; and the server-side createStreamableUI/RSC solution for streaming components during generation.
Architectural Patterns for Generative UI in React
You're adding generative UI — pick the architecture before the library: tool-JSON onto your component registry, declarative spec trees (A2UI/AG-UI), or sandboxed open-ended HTML; the spec layer, not the framework, is where the category is settling.
The field map above the Vercel reading's single pattern — three generative-UI architectures with working demos: (1) tool-constrained JSON mapped onto an existing component registry (Mastra + AI SDK), (2) declarative component-tree specs (A2UI v0.9) transported over the AG-UI protocol (CopilotKit demo) — native rendering with a safe payload, no arbitrary code execution, (3) open-ended LLM-emitted HTML/CSS/JS sandboxed in iframes via MCP Apps. Argues the interoperable spec layer (A2UI/AG-UI/MCP) is where the category is standardizing, over any one framework.
How to Build a Performant AI Markdown Renderer
You ship streaming LLM output — render markdown the Streamdown way: repair incomplete markdown before parsing, memoize at block level so every token doesn't re-parse, cache the processor, and wrap updates in startTransition.
The architecture behind streaming-markdown rendering (the Streamdown problem): repairing incomplete markdown before parsing, block-level memoization to avoid re-parsing every token, processor caching, and startTransition for smooth streaming.
Building a ChatGPT-Style AI Chat App in React Native with RAG & Streaming
You're building an AI chat UI in React Native — keep the JS thread free: decode streaming sockets, parse markdown, and fetch RAG natively; render the transcript with a chat-optimized list. Per-token JS-thread work is what makes streaming chat jank.
A production RN chat-app architecture (MargeloChat): stream OpenAI over WebSocket with UTF-8 decoding off the JS thread (react-native-nitro-websockets), native markdown parsing (Software Mansion's react-native-enriched-markdown), Legend List v3 for the transcript, keyboard-controller for composer tracking, true-sheet + liquid-glass for chrome, Pinecone RAG over nitro-fetch — 57-60fps by keeping every expensive step native or UI-thread. Margelo self-promotes its Nitro ecosystem throughout; the architectural principle stands independent of the vendor picks.
ai-devtools — AI-assisted development — agent skills, MCP tooling & device automation
3 Minutes With an Agent, 9 Seconds on Replay
You have an agent driving simulators or devices — the model, not the device, is the cost: a nine-action flow took 3m18s live and 8.8s on replay with zero model calls. Discover a flow once with the model, then replay it deterministically.
Measures where the time actually goes when an agent drives a device, and the answer is: not on the device. A nine-action QA task on an Android emulator took the agent 3m18s; saved as a replayable script and re-run with `agent-device replay` it finished in 8.8 seconds INCLUDING app launch, with zero model calls. Taps and snapshots were thin slices of the original run — the ~190-second gap is model inference, API round trips, screen reading and deciding what to do next. Two numbers make it actionable: in the opening run 2 of 29 tool calls were help lookups or rejected commands, and across an audit of 108 spontaneous runs 375 of 2,668 calls (14.1%) never reached the device at all. So the design rule for agent-driven device work is to spend model turns on DISCOVERING a flow once, then replay it deterministically for every repeat — the same split that makes recorded E2E cheap. Stated caveats: simulators/emulators on a workstation (no physical devices), load-gated timings for one experiment only, small + mid-tier models of one provider.
Testing Google's modern-web-guidance skill against a real React app
Your agent writes frontend code that was best practice three years ago — consult a curated guidance index (modern-web-guidance) before writing rather than reviewing after. It never reads your code: you still inventory, query, and judge whether a rule applies.
An independent field test of the option row above, and the honest scoping this category usually lacks. Pointed at a real Vite + React questionnaire app (42 files) it correctly flagged a hardcoded light theme with no color-scheme/prefers-color-scheme, data-entry surfaces with zero <form> elements, validation predating :user-invalid, and min-height:100vh where 100dvh is the modern answer — each with Baseline-checked, copy-pasteable guidance, and it also explicitly endorsed what the app already had right (fieldset/legend, role=alert, :focus-visible). The limits are the useful part: THE SKILL DOES NOT READ YOUR CODE — a human or an agent must inventory the codebase, turn each suspicion into a search phrase and compare the answer back to the actual lines; semantic search has a recall ceiling (dark-mode hit 0.75, but the dvh answer never surfaced as its own result, only inside broad omnibus guides); guides are large (forms ~4,500 tokens, accessibility ~7,100, both reported up front so you can weigh the fetch); and it returns general rules that may not apply — most of the input-attribute advice was irrelevant to a radio-driven form, and noticing that is the human's job. The author's reframe is the durable one: it is less a tool you run than a standard you consult, best used the moment BEFORE writing a component, when the model in the loop (human or AI) is about to reach for the pattern it already knows.
Bun is being rewritten in Rust
The largest published agent-driven port to date, and the methodology reading for agent fleets: Bun v1.4 ships a Zig→Rust rewrite of 535,496 lines executed by ~64 parallel Claude agents across 4 worktrees in ~50 workflows over 11 days (2026-05), ~$165k in API cost vs an estimated blocked engineer-year — with the load-bearing discipline that each implementer agent was paired with TWO adversarial reviewers in separate context windows told to assume the code was wrong.
Results: every instrumentable memory leak resolved (one bundler workload: 609MB stable vs 6.7GB before), ~20% smaller binaries, 2–5% faster. Not RN-specific, but the concrete data point for what adversarially-reviewed agent fleets can do to a production codebase — the review-pairing pattern transfers to any repo using the tools in this entry.
How Expensify Uses Agent-Device for Mobile Bug Evidence and Profiling
The first named production-adopter case study for agent-device: agents run Sentry-span measurement loops across branches and drive the React profiler mid-session via react-devtools integration, returning named components and render counts as bug evidence.
What agent-in-the-debug-loop looks like at a real company, beyond vendor demos.
Metrognome — An AI Agent for Measured React Native Performance Fixes
You point an agent at performance work — require it to measure N times against a noise floor and reject its own changes that don't beat it; an agent that only reports a diff has no way to tell an optimization from a coincidence.
The layer ABOVE the device-drivers in this entry: not another profiler or benchmark, but a loop that decides what to keep. For a given performance goal it proposes one hypothesis, runs the experiment, measures it N times on a live app, keeps the change only if it beats the noise, commits it with the evidence, then picks the next hypothesis — one variable at a time. It ships no profiler and no device driver of its own; it orchestrates the tools already listed here (Agent Device for eyes and hands, Agent React DevTools, and the rest of Callstack's stack) and contributes the research loop plus memory. VENDOR POST — nearly every organ carries a Callstack logo, and the numbers are theirs. The durable, transferable part is the discipline: an optimization agent that can REJECT its own work against a noise floor is a different thing from one that reports a diff.
Meet Argent: Agentic Toolkit to Control, Debug and Profile iOS applications
The clearest articulation of the closed loop this entry is about: the agent that writes the code also boots the simulator, drives the UI, attaches a debugger, and profiles React+iOS in the same session — with production numbers (~50% re-render reduction in a banking app) rather than demos.
Fable 5 vs GPT-5.6 Sol: I spent $2,000 and 2 billion tokens to find out who wins
You drive coding agents against an RN/Expo app — budget for the validation loop, not generation: per-feature on-simulator verification dominates token spend and is what makes one-shot quality possible; pick the model on measured cost-vs-speed, not vibes.
First-party measured model comparison on real Expo apps: three models (Fable 5/Claude Code, GPT-5.6 Sol/Codex, GPT-5.5 control) each one-shot three apps end-to-end — ideation, per-feature on-simulator validation, debugging — under the same spec-driven prompt and template. Fable 5 won code + UI quality (code-health 88 vs 79/79) at ~3× the hourly cost ($74/h vs ~$30/h) and ~30% less wall-clock; the dominant token cost across all models was the simulator-validation loop, not generation. The model numbers are point-in-time (2026-08-05); the durable part is the harness — standing quality bars plus per-feature simulator validation is what made one-shot apps work at all. (Fetched via browser-UA curl; expo.dev/blog no longer blocks it.)