How to build a React Native renderer backend
How to build a React Native renderer backend
Section titled “How to build a React Native renderer backend”Official docs still say creating a platform from scratch is “not very well documented,” and that New Architecture / Fabric exists partly to make that easier (Out-of-Tree Platforms).
1. Choose your path
Section titled “1. Choose your path”| Path | When to use | What you get | Cost |
|---|---|---|---|
| A. Fabric host platform | You want real RN apps (View/Text/TurboModules/codegen/Hermes) on a new OS or UI toolkit | Shared shadow tree, Yoga, diffing, JSI; you own mount + host views | Large: C++, run-loop, text, a11y, images, CLI/Metro |
B. react-reconciler host config | Custom React target (canvas, terminal, Three.js, PDF) without RN APIs | Your own host tree; no RN ecosystem by default | Medium: JS host config; unstable API |
| C. Fork / extend an existing OOT platform | Closest stack already exists (Windows Composition, GTK, Skia, GPUI) | Reuse mounting patterns, build, CLI | Still large; version-track upstream RN |
Rule of thumb: if the goal is “React Native on X,” pick A or C. If the goal is “React JSX driving X,” pick B (ink, react-three-fiber, react-pdf, Skia’s own reconciler, gtkx-style ports).
2. Fabric architecture (what a backend actually owns)
Section titled “2. Fabric architecture (what a backend actually owns)”Shared vs platform
Section titled “Shared vs platform”From Cross Platform Implementation: Fabric’s C++ APIs have two sides—(i) talk to React, (ii) talk to the host platform. Shared C++ owns shadow tree construction, Yoga layout (most of it), view flattening, and tree diffing. The host owns mounting host views and host events.
Grounded tree under packages/react-native/ReactCommon/react/renderer/ (facebook/react-native):
| Layer | Path | Role for a backend |
|---|---|---|
| Core / shadow nodes | renderer/core | Immutable shadow nodes, props, events |
| Component registry | renderer/componentregistry | ComponentDescriptorRegistry maps names → descriptors |
| Components | renderer/components | Built-in View/Text/… descriptors (codegen-fed) |
| Scheduler | renderer/scheduler | Scheduler, SurfaceHandler, SurfaceManager |
| Mounting (shared) | renderer/mounting | MountingCoordinator, Differentiator, ShadowTree, ShadowViewMutation |
| UIManager | renderer/uimanager | Binding toward JS / surface APIs |
| Text | renderer/textlayoutmanager | Platform hooks for measure |
| Images | renderer/imagemanager | Platform image pipeline |
| Runtime scheduler | renderer/runtimescheduler | Event-loop / priority scheduling |
| DOM helpers | renderer/dom | Layout/DOM-ish queries used by newer Web-aligned APIs |
Note on “MountingManager”: docs and older platform code use that name for the host UI applicator. In shared ReactCommon (2026 main), the cross-platform pieces are MountingCoordinator + ShadowViewMutation; platforms implement SchedulerDelegate and apply mutations to native views (RNW: ComponentView / FabricUIManagerModule).
Render → commit → mount
Section titled “Render → commit → mount”From Render pipeline and Threading model:
Mutation types (from ShadowViewMutation.h): Create, Delete, Insert, Remove, Update.
Platform callback surface (from SchedulerDelegate.h):
schedulerDidFinishTransaction/schedulerShouldRenderTransactions(flush viaMountingCoordinator)schedulerDidRequestPreliminaryViewAllocationschedulerDidDispatchCommandschedulerDidSendAccessibilityEventschedulerDidSetIsJSResponderschedulerShouldSynchronouslyUpdateViewOnUIThread/schedulerDidUpdateShadowTree- View-transition snapshot hooks
Threads (backend implications)
Section titled “Threads (backend implications)”- UI/main: only thread that mutates host views; mount runs here.
- JS: React render phase; can also run full pipeline synchronously for high-priority UI events.
- Layout mostly C++; Text / TextInput still call into the host for measurement (render pipeline).
New Architecture stack you also wire
Section titled “New Architecture stack you also wire”- JSI — direct C++ ↔ JS (no JSON bridge) (Fabric)
- Hermes — default engine; host embeds and drives its run loop
- TurboModules — lazy native modules + codegen
- Codegen — JS component/module specs → C++ props/structs; mismatches fail at build time
3. Implementation checklist (new Fabric platform)
Section titled “3. Implementation checklist (new Fabric platform)”Official Metro/platform registration only covers JS bundling (out-of-tree platforms): rnpm.haste.platforms, providesModuleNodeModules, .platform.js suffixes. Everything below is the native side the docs leave underspecified—filled from RNW Fabric + ReactCommon.
Must provide
Section titled “Must provide”- App / instance bootstrap — Hermes + JSI runtime, call into Fabric
Scheduler/SurfaceHandler, surface size/constraints. SchedulerDelegateimplementation — receive transactions; applyShadowViewMutationlist on UI thread.- Host component views — map shadow components to toolkit widgets (RNW:
vnext/Microsoft.ReactNative/Fabric/Composition/*ComponentView.cpp). ComponentDescriptorregistration — platform + third-party descriptors intoComponentDescriptorRegistry/ provider registry (RNW:WindowsComponentDescriptorRegistry,AbiComponentDescriptor).- Text measurement — implement host side of
TextLayoutManager(RNW uses DirectWrite helpers:DWriteHelpers.*). - Event emitters — touch/pointer/keyboard → Fabric event system (RNW:
AbiEventEmitter, Composition event handlers). - Run-loop / RuntimeScheduler integration — pump JS microtasks, mount flushes, animations on the right threads (RFC0744 event loop).
- Image loading — platform
ImageManager(RNW:WindowsImageManager.cpp). - Accessibility — map props +
schedulerDidSendAccessibilityEventto OS a11y (RNW Composition root automation providers). - TurboModules + codegen — PlatformConstants, Linking, Appearance, AsyncStorage, …; wire
@react-native/codegen. - Metro / CLI — platform name,
react-native.config.js,run-<platform>, autolinking story. - Core primitives parity — View, Text, Image, ScrollView, TextInput, Modal, Switch, Pressable at minimum before claiming “RN on X.”
Reuse from ReactCommon
Section titled “Reuse from ReactCommon”Shadow tree, Yoga, Differentiator, MountingCoordinator, ComponentDescriptor machinery, attributed strings, bridging, UIManager bindings, most of renderer/components. Do not reimplement diffing in the host.
Build setup (patterns that work)
Section titled “Build setup (patterns that work)”- CMake + Ninja for Linux-style hosts (lucid-softworks/react-native-linux mirrors RNW’s
vnext/layout). - RNW: MSBuild / NuGet prebuilts for New Arch apps (New vs Old Architecture).
- Link Folly, glog, fmt, Yoga, Hermes; keep version pins aligned with the RN release you target.
- Watch RFC1018 C++ Strict API — out-of-tree platforms will need the stable C++ surface, not private headers.
Testing story
Section titled “Testing story”- Unit-test mutation application and layout against golden trees (RN ships
renderer/mounting/tests,scheduler/tests). - Smoke / playground app (RNW
playground-composition, linuxapps/playground). - E2E against RN Tester–like galleries; track parity matrices (RNW issue #12042).
- Third-party library canaries (Paper, Reanimated, gesture-handler) early—ecosystem breakages dominate schedule.
4. Path B — react-reconciler host config
Section titled “4. Path B — react-reconciler host config”From react-reconciler README: experimental; API does not follow React’s semver.
Enough when: you do not need RN component APIs, TurboModules, or Metro’s RN resolution—e.g. react-three-fiber, ink, react-pdf, Skia canvas reconcilers, native-surface (Yoga+CanvasKit via reconciler), gtkx-style GTK ports.
Not enough when: you want unmodified RN apps / libraries—those assume Fabric host components + JSI modules.
Modes
supportsMutation: true— DOM-like (React DOM, classic RN, R3F)supportsPersistence: true— immutable trees (Fabric’s React host config style)
Core methods (mutation mode, incomplete but stable-ish): createInstance, createTextInstance, appendInitialChild, appendChild, appendChildToContainer, removeChild, insertBefore, commitUpdate, commitTextUpdate, finalizeInitialChildren, prepareUpdate, getRootHostContext, getChildHostContext, getPublicInstance, shouldSetTextContent, scheduleTimeout / cancelTimeout, noTimeout, plus commit hooks (commitMount, etc.). Full list: ReactFiberConfig (linked from the README).
5. Existing backends to study (status as of 2026-10)
Section titled “5. Existing backends to study (status as of 2026-10)”Fabric / out-of-tree RN platforms
Section titled “Fabric / out-of-tree RN platforms”| Project | Repo | Status (2026) | Notes |
|---|---|---|---|
| react-native-windows | microsoft/react-native-windows | Production path; New Arch default for new apps since 0.80; Old Arch deprecated with RN 0.82 | Fabric on Windows App SDK Composition (not WinUI XAML). Study vnext/Microsoft.ReactNative/Fabric/. Docs: new-architecture. Hub: #12042 |
| react-native-macos | microsoft/react-native-macos | Partner OOT (listed on reactnative.dev) | Cocoa / AppKit lineage |
| react-native-visionos | callstack/react-native-visionos | Partner | visionOS |
| react-native-tvos | react-native-tvos/react-native-tvos | Community | Apple TV / Android TV |
| react-native-web | necolas/react-native-web | Mature | RN API → DOM; not Fabric C++ |
| React Native Skia (OOT) | listed on out-of-tree platforms | Linux/macOS Skia renderer | Distinct from Shopify’s in-app Skia graphics lib |
| react-native-linux (GTK4) | lucid-softworks/react-native-linux | Alpha (created 2026-05); Hermes + Fabric-only; modeled on RNW vnext/ | TurboModule codegen not fully wired; good structural reference |
| react-native-gtkx | itsmepetrov/react-native-gtkx | Active experiment | RN API via react-reconciler → GTK4/Adwaita (web-like alias), not full Fabric C++ |
| react-native-gpui | Announced by @ammarahm_ed (2026-10-02) | Pre-alpha / coming soon | Fabric → Zed GPUI (Rust); positioned like RNW (“reuse RN architecture, add platform”) |
Reconciler / alternate renderers
Section titled “Reconciler / alternate renderers”| Project | Approach |
|---|---|
| shopify/react-native-skia | Skia drawing inside RN (Fabric/JSI), not a full OOT platform |
| pmndrs/react-three-fiber | react-reconciler → Three.js |
| vadimdemedes/ink | Reconciler → terminal |
| native-surface | Reconciler + Yoga WASM + CanvasKit; RN-compat layer in browser |
| roman01la/cljs-static-hermes | Static Hermes AOT + Skia/Yoga custom reconciler (HN-adjacent experiments) |
6. Pitfalls
Section titled “6. Pitfalls”- Text layout — hardest host dependency; every platform reinvents measurement (Core Text, DirectWrite, Pango, Skia text). Yoga defers here.
- Threading — mounting off the UI thread = crashes; JS↔UI priority interrupts must match RuntimeScheduler / event-loop RFC.
- Upstream drift — OOT platforms pin an RN version and chase every release; New Arch is default since 0.76 (blog).
- Codegen / autolinking — without it, third-party Fabric components and TurboModules do not appear (linux alpha explicitly lacks full codegen wiring).
- Maintenance cost — RNW’s multi-year Fabric port (Composition, XAML islands, custom component ABI) is the honesty check; “hello View” is weeks, ecosystem parity is years.
- Lean Core — more modules leave core; your platform must ship or stub what apps expect (see RFC0836 Lean Core JSC and ongoing lean-core direction).
- DOM APIs on Fabric — RFC0607 + shipping
IntersectionObserver(canary/experimental docs) assume Fabric’s intermediate tree; Paper-only or reconciler-only backends will not get these “for free.” Shared helpers live underrenderer/dom. - Static Hermes — AOT / native compilation experiments exist (cljs-static-hermes, Attar on HN); not a drop-in replacement for embedding Hermes in a new OOT platform yet—plan for standard Hermes first.
- C++ API stability — prefer documented / Strict API surfaces (RFC1018); private ReactCommon headers will break you.
7. Field notes
Section titled “7. Field notes”- @ammarahm_ed on X (2026-10-02): react-native-gpui “is an out-of-tree react-native renderer much like react-native-windows that reuses the complete react-native architecture as-is, only adding a new gpui platform… RN’s core is platform agnostic.” Follow-up demos claim Reanimated/worklets on the UI thread (2106314150070948015).
- @theultdev (2026-10-03): argues GPUI-style one renderer is preferable on Linux because “react-native-gtk and react-native-qt failed”—tension with native-widget purity vs shared GPU UI.
- RNW Fabric authors (e.g. Composition PRs by acoates-ms): host XAML islands inside Composition, expose
(un)MountChildComponentViewto 3P components—pattern for custom host views without inheriting across DLL boundaries (PR #13603, commit exposing mount APIs). - Official stance: partners list macOS / Windows / visionOS; community list tvOS / web / Skia; “from scratch still not very well documented” (docs).
- discussions-and-proposals: use RFC496 React DOM for Native, RFC0607, RFC0744 event loop, RFC1018 C++ Strict API—not a single “how to build a platform” RFC.
- HN / experiments: custom reconciler + Static Hermes / Skia remain niche (romanliutikov writeup); little HN traffic specifically on “Fabric OOT platform how-to” as of search on 2026-10-06.
8. Sources
Section titled “8. Sources”Primary docs
Section titled “Primary docs”- Fabric
- Render, Commit, and Mount
- Threading Model
- Cross Platform Implementation
- Out-of-Tree Platforms
- RN 0.76 — New Architecture by default
- RNW New vs Old Architecture
- IntersectionObserver (experimental)
Source trees
Section titled “Source trees”- ReactCommon/react/renderer — mounting, scheduler, componentregistry, textlayoutmanager, imagemanager, dom
SchedulerDelegate.hShadowViewMutation.h- RNW Fabric/
- react-reconciler README
Community / proposals
Section titled “Community / proposals”- discussions-and-proposals
- RFC0607 DOM traversal
- RFC0744 event loop
- RFC1018 C++ Strict API
- RFC496 React DOM for Native
Field / experiments
Section titled “Field / experiments”- X: react-native-gpui announcement, architecture clarification
- lucid-softworks/react-native-linux
- itsmepetrov/react-native-gtkx
- HN Algolia (2026-10-06): weak hits on Fabric OOT; stronger on Static Hermes / custom reconciler experiments
Gaps (research limits)
Section titled “Gaps (research limits)”- No single official “implement MountingManager” tutorial; platform mounting is inferred from ReactCommon + RNW.
- GitHub code search for
MountingManagerreturned incomplete/empty in this session; claims useMountingCoordinator/SchedulerDelegate/ RNWComponentViewinstead. - Reddit
site:reddit.comExa queries returned noise / empty for OOT Fabric; field notes leaned on X + GitHub. - Static Hermes doc path on
static_hbranch did not fetch cleanly; treated as experimental only. - Exact production readiness of “React Native Skia” as listed on reactnative.dev vs Shopify’s library should be re-checked before depending on it.