Skip to content
AI SI Daily
中文

Search the site

↑↓ Select · Enter Open · Esc Close

○ Overview

nsh (Native Shell): Longbridge's Rust cross-platform UI, explained for frontend devs

Longbridge's nsh (Native Shell) for frontend devs: TSX with signals, native views, hot reload, AI-agent tooling, and a comparison with React Native, Flutter and Tauri.

Liang Cui (滴滴点到)Tested: Debian 13 VM, 8 vCPU, 15 GB RAM, headless Google Chrome 156 (2026-11-01). No iOS, Android, macOS, Windows or GTK window tested.
This is an overview compiled from the official website, documentation and GitHub README. We have not tested it ourselves. Features and pricing are subject to the official pages; sources are listed at the end.

nsh, short for Native Shell, is a cross-platform UI framework from the brokerage app maker Longbridge (长桥). You write an app in Rust, in TSX, or in both, and nsh renders it with each platform’s own UI toolkit on iOS, Android, macOS and Linux. Windows uses NSH’s own Direct2D drawing, and the web gets plain HTML elements. The repository is Apache-2.0 and was 18 days old when we wrote this. It has had four releases, and two of them broke the API.

For frontend developers, three things matter. The TSX looks like React but is not React: components run once and signals drive updates. Longbridge says it will move every H5 page in its mobile apps to nsh. And most commits are co-written with AI agents, with the docs published as llms.txt for agents to read.

Short version: nsh is worth a weekend prototype if you want one TSX or Rust codebase on phones, desktops and the web without a web view. It is too young to bet a product on until the API stops changing.

What nsh is

The project calls itself “a Rust-first native UI framework”. Its docs say apps are written “in Rust (compiled to native code) or TSX (run by QuickJS, and by the browser’s JavaScript engine on the web), or both”. The engine shared by every platform is Rust. Layout uses Taffy (flexbox and grid) on every platform, and the reactive core follows the algorithm of Solid 1.9, according to the architecture doc.

Each platform has its own backend. The minimums below come from the project’s comparison page:

Target What draws the UI Minimum
iOS UIKit iOS 15
Android Android views Android 9 (API 28)
macOS AppKit macOS 14
Windows NSH’s own drawing with Direct2D/DirectWrite Windows 10 1809
Linux GTK 4 GTK 4.14
Web HTML elements styled with CSS A current browser
GPUI Embeds nsh apps in GPUI and GPUI Kit apps Desktop

Jason Lee (@huacnlee), the most active committer, put it this way on X (2026-10-25, 15:43 UTC+8): “除 Windows 之外,各平台都不是自绘 UI” (apart from Windows, no platform draws its own UI). That is why he expects text input, scrolling, text selection, input methods and accessibility to behave as they do in each platform’s own apps.

How you write UI in nsh, as a frontend developer

This is the counter that nsh init my-app --template ts generated for us with nsh 0.3.0:

import { mount, signal, Text, View } from "nsh";

function App() {
  const count = signal(0);
  return (
    <View class="flex-1 pt-[env(safe-area-inset-top)] pr-[env(safe-area-inset-right)] pb-[env(safe-area-inset-bottom)] pl-[env(safe-area-inset-left)] items-center justify-center gap-4 bg-background">
      <Text class="text-3xl font-semibold text-foreground">{count()}</Text>
      <View
        onPress={() => count.update((c) => c + 1)}
        role="button"
        class="rounded-(--radius) bg-primary px-5 py-3 active:bg-primary/90"
      >
        <Text class="text-lg text-primary-foreground">Tap</Text>
      </View>
    </View>
  );
}

mount(App);

The template also ships a test that runs headless:

import { expect, open, test } from "nsh/test";

test("counts taps", async () => {
  const app = await open("./App.tsx");
  expect(app.texts()).toContain("0");
  await app.press("Tap");
  await app.press("Tap");
  expect(app.texts()).toContain("2");
});

If you come from React or React Native, these are the differences:

  • No React, no virtual DOM. The architecture doc says “Components run once. Only bindings re-run; there is no re-render of a component and no virtual DOM diff.” If you know Solid, signal(), count() and count.update() will look familiar. If you only know React hooks, plan on re-learning when code runs.
  • Not HTML either. You write View and Text, with onPress, the way React Native does. Lee replied to a user on X that it is “不是 HTML + CSS 这是我们特有的 DSL,只是看起来像 TSX” (not HTML and CSS; it is our own DSL that only looks like TSX). In v0.2.0 the project replaced its React Native-shaped API with its own names.
  • Tailwind classes are the main styling API. class takes Tailwind utilities, and style={{ ... }} takes camelCase style objects. The theme uses shadcn/ui tokens (bg-primary, text-foreground). The Tailwind classes are resolved in Rust at run time, so there is no PostCSS step.
  • No Node.js. The single nsh binary bundles TSX with Oxc, its own JSX compiler and rolldown, and compiles it to QuickJS bytecode. nsh check downloads TypeScript’s native compiler once from npm and still needs no Node.
  • Components come unstyled. nsh/base gives you behavior (navigation, dialogs, menus, tabs, tables, editors), and your app supplies the look. The goals doc says styled components belong to “the app or a community library”. There is no shadcn-style kit in the box.

Quickstart

From the getting-started docs and release notes:

# macOS / Linux (Homebrew: brew install longbridge/tap/nsh)
curl -fsSL https://nsh.dev/install.sh | sh
# Windows PowerShell: irm https://nsh.dev/install.ps1 | iex

nsh init my-app --template ts          # or: rust, mixed
nsh run my-app                         # AppKit on macOS, GTK on Linux, Win32 on Windows
nsh run my-app --target web            # or: ios, android, gpui, catalyst
nsh test my-app                        # headless tests
nsh package my-app/App.tsx --target web

Prebuilt downloads exist for Linux x86_64, macOS arm64 and Windows x86_64, plus iOS and Android embed kits. We found no Intel Mac build on the v0.3.0 release page.

What we ran on a Linux box

We did not test nsh on a phone, a Mac or Windows. On 2026-11-01 we installed the prebuilt nsh 0.3.0 on a Debian 13 VM and ran the CLI and the web target only. These are our measurements:

  • The installed distribution took 451 MB on disk.
  • nsh init created the app above. nsh build reported “1.1 KB js, 3.0 KB bytecode, 6ms”.
  • nsh test passed the template test headless: “1 test: 1 passed, 0 failed (322ms)”.
  • nsh package --target web produced a 13.1 MB static folder. Most of it was a 13.6 MB nsh.wasm file, 4.7 MB with gzip -9.
  • In headless Chrome 156 the page rendered and two clicks took the counter to 2. The DOM held 6 div and 2 span elements, no canvas, each placed with inline left, top, width and height.
  • The native GTK window did not start. The Linux runtime also needs WebKitGTK 6.0, and the package install failed on our VM, so we have no desktop result.

The logs and screenshots are in our evidence folder. The wasm size needs context, covered in the next section.

The web target: real HTML, with NSH doing the layout

Lee says nsh on the web is “not the wasm. All are HTML + JavaScript” (X, 2026-10-19, 20:22 UTC+8). @PeterKogo2 replied: “Why is there a 1.3mb wasm loaded and most of the frametime is spent in wasm?”

Both are partly right. The elements are HTML, so the browser handles scrolling, text selection and input. But the web doc says “WebAssembly hosts the shared Rust engine for component state, layout and updates”. Our DOM check matches that: Taffy computes positions in Rust and writes them as absolute coordinates, so the browser’s CSS flexbox does not do the layout. A frontend developer debugging layout in DevTools will see pixel offsets, not display: flex.

The size question depends on the version. In the v0.3.0 docs, a TSX web app ran QuickJS inside the wasm, at “about 3.5 MB, 1.2 MB gzipped”. Our v0.3.0 build was much larger, and we did not find out why. On 2026-10-28, after v0.3.0, PR #603 moved TSX web apps to the browser’s own JavaScript engine. The current docs say an app built from the core components “downloads about 1.1 MB”. That change had not shipped in a release as of 2026-11-01.

Hot reload and the dev loop

nsh run and nsh dev start a host with hot module replacement. The dev-server doc says TSX edits are patched “in well under a millisecond; from saving a file to seeing the change takes roughly 120 ms”. Components whose code did not change keep their state. Rust edits rebuild and restart the app. These are project figures. We did not test hot reload.

Built with AI agents, and for them

The AI angle has evidence behind it in two places: how nsh is built, and what it is for.

  • Docs for agents. The docs are served as llms.txt and llms-full.txt, and every page has a Markdown copy. TypeScript declarations for every element, prop and style key are generated from the Rust sources into .nsh/types, so a compiler checks code that an agent writes.
  • Tailwind, partly for token cost. Lee wrote (2026-10-20, 21:54 UTC+8): “for AI, the Tailwind API is less token cost.” That is his opinion. We have seen no measurement.
  • AI-generated UI shipped after release. A host app can download TSX as a signed .nshpkg package and run it in a sandbox. The sandbox doc lists limits on memory, time per call and nodes kept, plus capabilities the host grants. Lee’s launch post (2026-10-19, 18:57 UTC+8) says Longbridge would start using nsh in its mobile app that week, “主要解决 AI 动态生成模块支持” (mainly to support AI-generated dynamic modules).
  • Most commits are co-written with AI. In our clone (640 commits, up to 2026-11-01 21:20 UTC+8), 518 commits carry an AI co-author trailer or a “Generated with Claude Code” line. The most common trailer is “Co-authored-by: Claude Opus 5.5”, with 353 commits. Codex, Devin and GitHub Copilot’s agent also appear. The repo has a 614-line AGENTS.md, and CLAUDE.md only points to it. Lee says the project gets “每天有超过 50 个 PRs” (over 50 PRs a day) (X, 2026-10-29).

For a frontend team the useful part is the loop. One CLI can create, type-check, test headless and package, which makes it practical to let an agent write a screen and check it. The risk is the flip side: an API written this fast by agents can change just as fast.

Where nsh comes from: GPUI, GPUI Kit and gpui-component

Longbridge already maintains GPUI Kit (formerly gpui-component, about 18,800 GitHub stars), a component set for Zed’s GPUI, and GPUI Fast, its GPUI fork. GPUI draws everything itself on the GPU.

The nsh docs say nsh began as a plugin layer for Longbridge’s mobile client, starting from GPUI Shell. On phones, a self-drawn UI “would have had to rebuild what the platform already does: text selection and its menu (Copy, Share, Translate, Look Up), input methods, accessibility”. Lee gave the same reasons on X: native text selection, translation and autofill, multi-touch, and battery cost under GPUI’s immediate mode.

The two projects split the work like this. GPUI Kit stays the choice for self-drawn desktop apps. nsh’s nsh/base follows the unstyled gpui-base model, and its GPUI backend can embed nsh apps inside GPUI Kit apps. When @tdomhan asked whether GPUI Kit would stop being developed, we found no public answer.

nsh vs React Native, Flutter, Tauri and Electron

nsh React Native Flutter Tauri Electron
What draws the UI Platform UI (own drawing on Windows) Platform views Its own engine The system web view Bundled Chromium
You write UI in TSX with signals, or Rust JS/TS with React Dart Any web framework Any web framework
JS runtime in a native app QuickJS for TSX; none for Rust apps Yes None The web view’s Chromium + Node.js
Mobile iOS 15+, Android 9+ iOS 15.1+, Android 7+ iOS 15+, Android 7+ Yes (Tauri 2) No
Desktop macOS, Windows, Linux Via separate macOS/Windows projects macOS, Windows, Linux macOS, Windows, Linux macOS, Windows, Linux
Web HTML elements Via react-native-web Canvas It is web content It is web content
License Apache-2.0 MIT BSD-3-Clause MIT or MIT/Apache-2.0 MIT

Sources: nsh’s comparison page, which cites React Native 0.76 and Flutter’s supported platforms; Tauri’s docs; Electron’s docs; and each project’s license on GitHub.

nsh’s own page lists when another choice fits better. Pick Flutter or Slint when the UI must look pixel-identical everywhere. Pick React Native, Flutter or Qt when you need a large package ecosystem. Pick GPUI Fast for sustained, dense updates.

Lee does not think much of the web-based options. “如果你还在考虑 Electron, Tauri 这些工具,那应该赶紧放弃” (if you are still considering Electron or Tauri, drop them now), he wrote on 2026-10-26 (09:25 UTC+8). That is a maintainer’s opinion, not a measurement.

Performance: project claims only

We did not benchmark nsh. The numbers below are the project’s own.

  • The comparison page cites the nsh-perf-bench repository (Linux, a 500-row quote table, GTK backend). At 1,000 quotes a second, NSH Rust uses 18% of a core and GPUI Fast 20%. At 20,000 quotes a second, GPUI Fast uses 25% and NSH 73 to 78%.
  • Lee posted Gallery “Stocks” demo figures: 120 FPS at 33 to 36% CPU on an M3 Mac, 117 to 120 FPS at 31 to 32% on Linux with NVIDIA, and 144 FPS at 36 to 43% on Windows.

Limits and risks

  • The API is still moving. v0.2.0 (2026-10-22) and v0.3.0 (2026-10-26) both list breaking changes. The compatibility doc promises that “an app built for a compatible release runs on every later release, unchanged”. That record lives in a separate nsh-compat store we did not inspect, so it is not clear which releases it covers yet.
  • The project is very young. The first commit is dated 2026-10-14. On 2026-11-01 the repo had 914 stars and 72 open issues. GitHub’s API reports the license as “NOASSERTION”, while the repo ships an Apache-2.0 file.
  • “Cross-platform” still means per-platform builds. @trymorewz noted that “’跨平台’也不等于一次编译出所有安装包,桌面应用仍需在对应系统打包” (cross-platform does not mean one build produces every installer; desktop apps still need packaging on each OS).
  • Windows is the exception to “native”. Windows uses NSH’s own Direct2D drawing.
  • The web runtime is heavier than plain HTML. See the wasm numbers above. Check the size for the release you ship.
  • Linux has rough edges. One user replied “linux环境下bug有点儿多” (quite a few bugs on Linux). Another said llms.txt still pointed to an older version, so their agent pinned the wrong release.
  • HarmonyOS is unconfirmed. Lee said someone opened a HarmonyOS pull request, and that he was undecided.

How people reacted on X

Most replies we found were in Chinese, under Lee’s posts:

  • @xiaoshan0413 summed up the trade-off: “重性能拼定制就选GPUI,要快要跨端就选Native Shell” (pick GPUI for performance and customization, Native Shell for speed and cross-platform reach).
  • @maddada wrote: “TypeScript feels like ‘ew’ for desktop or mobile apps 😅 Any performance comparasions between Native Shell and GPUI?”
  • @faywanghq, who said he had built a C++ Skia-based framework, asked whether nsh only takes the container view from each platform and draws the children itself, since otherwise he did not see how it keeps features equal across so many platforms.
  • @sufunds described Vela, a macOS and iOS app built with nsh that reaches a Mac’s local dev servers from an iPhone over Tailscale.
  • @thejingtao said “我在用 NSH 做 Generative UI 了,效果非常好” (I’m using NSH for generative UI and it works very well).
  • @emojiiii007 asked how dynamic updates work if nsh builds native code. The answer in the docs is the signed TSX package path described above.

What this means for frontend developers

The H5 migration post (2026-10-28, 10:30 UTC+8) is the line to read twice: “Longbridge 接下来会将所有手机客户端里面的 H5 逐步淘汰迁移改造,改用 NSH 来实现。以后将不再需要用前端来开发这些动态更新的手机界面” (Longbridge will gradually phase out all H5 in its mobile clients and rebuild it with NSH; these dynamically updated mobile screens will no longer need web frontend development). We have no timeline beyond that post.

The skills still carry over. You keep TSX, Tailwind, flexbox thinking and a test runner. You give up React, npm packages that touch the DOM, and CSS that the browser lays out.

Our current take: nsh tries to keep H5-style dynamic delivery while rendering native views on every platform, and Longbridge is putting its own app on it. Its agent-driven pace is also its main risk. Try the TSX path on one screen, pin the version, and watch the compatibility record before you plan a migration.

Primary sources