Skip to main content

What Basalt is

Basalt runs React Native apps on the desktop — Linux, macOS and Windows — on React Native's own C++ core rather than on a browser engine.

Each desktop gets a host written against its native toolkit: GTK4 on Linux, AppKit on macOS, Win32 with Direct2D and DirectWrite on Windows. A <View> is a real widget on each. Text is laid out by Pango, Core Text or DirectWrite, so Yoga sizes a paragraph the way it does on iOS and Android and narrowing the window re-wraps it. The app ships as one binary with no bundled browser.

What runs underneath is React Native's, not a reimplementation of it: Hermes, Yoga, Fabric and the shadow tree are the same C++ that runs on a phone. Basalt supplies the part ReactCommon declares and does not define — a component registry, a mounting manager and a text layout engine per platform — which is why your components, props and layout behave as they already do.

How this differs from the alternatives​

Electron and Tauri give you a web view. You write web UI, and the layout engine is a browser's. Basalt gives you the React Native component model and native widgets; there is no DOM and no CSS.

react-native-windows and react-native-macos are Microsoft's and Meta's own desktop forks, each a separate repository with its own release cadence. Basalt is one project covering three desktops, and deliberately uses their platform names — macos and windows — so a library shipping Button.macos.js resolves here without knowing Basalt exists.

Expo is not an alternative; it is the common case. A stock Expo app runs, and basalt init writes the Metro config on expo/metro-config when it finds one.

What works today​

The components below are registered by every host and mount to real widgets. Pressable and the Touchable* family are composed from View and work with them.

Viewborders and per-corner radii, transform, zIndex, overflow, display
Textlaid out and measured by the platform's own text engine
Imagefiles, http(s), data: URIs, decoded off the main thread, resizeMode
ScrollViewclipping, scrollTo, scrollToEnd, onScroll reporting back to React
TextInputa real native editor, so input methods, selection and the clipboard come with it
Switch, ActivityIndicator, Modal, RefreshControl

Accessibility reaches the platform's accessible layer: accessibilityRole, accessibilityLabel, accessibilityHint and accessibilityState are mapped, and a <Text> calls itself a label without the app saying so.

Third-party native modules work — react-native-gesture-handler and Reanimated both run — and an app can contribute its own C++ without publishing a package. See Native modules.

What to expect​

Basalt is published as 0.0.0-rc prereleases. Being specific about the limits is more useful than a maturity label:

  • React Native 0.86 and 0.87 are supported, and 0.87 is what CI pins. 0.83–0.85 have never been built or tested; 0.82 and older were attempted and deliberately stopped. See Supported versions.
  • On 0.86 there is no Fast Refresh. A teardown leaves the host without a mounting manager, so a reload collapses it. Root-caused and fixed upstream in 0.87 — so use 0.87 if you want it.
  • The first build compiles Hermes and React Native's C++ from source and takes tens of minutes. Later builds do not.
  • Windows registers one fewer component than the other two, because nothing there mounts an ExpoImage yet.

Where to go next​

  • Getting started — prerequisites, one command, and what it changes.
  • CLI reference — every command, option and default.
  • app.json — which desktops to build, the bundle identifier, URL schemes.
  • APIs — the few things Basalt adds that React Native has no equivalent for, because a phone has no such thing.

The repository's own documentation, under Contributing, is written for people working on Basalt rather than with it — but it is the most detailed account of how any of this works, and Decisions records why it is built this way.