Rust-Backed Engine
Layout and ANSI rendering run natively in a Rust .node addon. No JavaScript on the hot render path. No garbage collection pauses mid-frame.
BetterTUI wraps a memory-safe Rust engine in a thin TypeScript API. Build terminal interfaces with React or SolidJS — no garbage collection pauses, no memory leaks, no bundle bloat. Designed for Node.js first, Bun compatible.
import { Box, Text, useInput } from "@bettertui/react";
import { render } from "@bettertui/core";
function App() {
useInput((key) => { if (key === "q") process.exit(0); });
return (
<Box flexDirection="column" padding={1}>
<Text bold color="green">● BetterTUI — Rust-powered TUI</Text>
<Text dimColor>Node-first · Memory-safe · v0.0.0-beta</Text>
</Box>
);
}
render(<App />);Runtime & Framework Support
Vue · Svelte · Preact · and more — planned for future releases
Features
Built from first principles — not as a feature list, but as a coherent set of technical decisions.
Layout and ANSI rendering run natively in a Rust .node addon. No JavaScript on the hot render path. No garbage collection pauses mid-frame.
Designed for Node.js ≥ 24 with stability as the first priority. Bun compatible when you need it — no runtime surprises, no polyfills.
Proper reconciler adapters for React 19 and SolidJS — not thin wrappers, not adapters bolted on. Framework primitives map directly to the engine.
The Rust engine uses arena allocation with generational indices. Memory leaks in the render pipeline are impossible by construction.
The heavy lifting lives in the native addon — entirely outside your JS bundle. The TypeScript layer is deliberately thin and tree-shakeable.
Complete type inference from JSX props to the native bridge. No `any`, no guessing. Autocomplete and compile-time safety everywhere.
How it works
Write components exactly like you would for the web. BetterTUI translates them to the terminal through its Rust engine.
import { Box, Text, useInput } from "@bettertui/react";
import { render } from "@bettertui/core";
function App() {
useInput((key) => {
if (key === "q") process.exit(0);
});
return (
<Box flexDirection="column" padding={1}>
<Text bold color="green">Count: {count}</Text>
<Text dimColor>Press q to quit</Text>
</Box>
);
}
render(<App />);Terminal output
See it in action
The Rust engine initialises on first import. No configuration. No build step.
How It Works
A memory-safe Rust engine underneath a TypeScript-first API. Every layer has a single responsibility.
Layer 1
Framework Adapters
React 19 + SolidJS · First-class reconcilers
Layer 2
@bettertui/core
CommandBuffer · Runtime · Tree Reconciliation
A thin, intentional TypeScript layer. Orchestrates the bridge between your framework and the native engine.
Layer 3
Rust Engine
Taffy Layout · ANSI Renderer · Arena Allocator
The hot render path runs natively. No garbage collector pressure. Arena allocation with generational indices means no memory leaks possible.
Why BetterTUI
Built from the ground up on memory-safe Rust — because existing tools made the wrong tradeoffs, and production TUIs deserve better.
The Origin
BetterTUI was born from direct experience with OpenTUI — an impressive library that proved the TypeScript ecosystem deserves a first-class TUI framework. But using it in real applications revealed two hard constraints: a Bun runtime requirement and a Zig-backed terminal layer. Both are remarkable engineering achievements. Neither is a foundation you'd build production software on when stability is non-negotiable — Bun is still experimental with known compatibility gaps, and Zig's memory model brings hazards that compound under real workloads.
That raised a single question: what if we built this right, from scratch, on the most memory-safe foundation available? The answer is Rust — not as a trend, but as the only language where memory leaks and data races are impossible by construction.
Runtime
Bun — experimental
Node.js ≥ 24 — stable
System Layer
Zig — memory hazards
Rust — safe by design
Memory Model
GC pauses mid-frame
Arena allocation, no GC
Bun is fast but experimental — unpredictable behavior, incomplete Node.js compatibility, and sharp production edges. Zig-backed terminals carry known memory hazards that surface under load.
Our solution
Node.js ≥ 24 as the primary target. The Rust engine eliminates memory hazards by construction — no manual allocations, no use-after-free, no runtime surprises.
Pure-JS TUI renderers compete with your app for the garbage collector. A 50ms GC pause in a real-time dashboard is visible and jarring.
Our solution
The Rust engine never touches the JS heap. Layout and rendering are garbage collection–free by construction.
Traditional TUI libs ship the full rendering engine in JS — parsing, layout, ANSI encoding. That's hundreds of kB in your bundle.
Our solution
The JS layer is a thin orchestration bridge. All the heavy work lives in the native addon — entirely outside your bundle.
Ink is React-only. Blessed has no modern framework adapters. You either fight your framework or give up features.
Our solution
First-class adapters for React 19 and SolidJS. Same Rust engine, same API, different reconciler.
Every feature BetterTUI ships is validated against OpenTUI's complete example suite. If OpenTUI can demonstrate it, BetterTUI must match or exceed it on a stable, memory-safe foundation. Their examples are our acceptance criteria and our definition of done.
A sincere thank you to every contributor who built OpenTUI. Your work demonstrated what was possible in the TypeScript ecosystem, gave us our benchmark, and motivated building something the entire community can rely on. This project exists because of your effort.
⚠ Early Beta — v0.0.0
BetterTUI is not production-ready. The API is unstable and actively evolving. We're sharing early to collect feedback from the community.
We're in early beta and actively refining the API with early adopters. Star the repo, try it out, and tell us what's broken.
Apache 2.0 licensed · Built in public on GitHub