Installation
npm install @rezi-ui/node @rezi-ui/core
Overview
@rezi-ui/node provides a production-ready backend for running Rezi applications on Node.js (18+) and Bun (1.3.0+). It includes:
Worker-thread based rendering engine
Terminal I/O management
Hot state reload for development
Image loading utilities
Stream adapters for useTail, useWebSocket, etc.
Quick Start
import { createNodeApp } from "@rezi-ui/node" ;
import { ui } from "@rezi-ui/core" ;
type State = { count : number };
const app = createNodeApp < State >({
initialState: { count: 0 },
});
app . view (( state ) =>
ui . page ({ p: 1 }, [
ui . text ( `Count: ${ state . count } ` ),
ui . button ({ id: "inc" , label: "Increment" }),
])
);
app . on ( "press" , ( evt ) => {
if ( evt . id === "inc" ) {
app . update (( s ) => ({ count: s . count + 1 }));
}
});
await app . run ();
API Reference
createNodeApp
Create a fully configured Rezi app with Node.js backend.
options
CreateNodeAppOptions<S>
required
Configuration object for the app.
Initial application state.
Optional route definitions for page router.
Initial route path (default: first route).
Theme to use. Automatically converts to NO_COLOR when NO_COLOR env var is present.
Optional configuration for app and backend behavior.
Frame rate cap (default: 60). Set to 30 for production apps to reduce CPU usage.
options.config.executionMode
Execution mode (default: ‘worker’). Use ‘inline’ for debugging.
options.config.drawlistVersion
ZRDL protocol version (default: 5).
options.hotReload
NodeAppHotReloadOptions<S>
Development hot reload configuration.
Returns : NodeApp<S> - App instance with backend attached.
import { createNodeApp } from "@rezi-ui/node" ;
import { darkTheme } from "@rezi-ui/core" ;
const app = createNodeApp ({
initialState: { users: [] },
theme: darkTheme ,
config: {
fpsCap: 30 , // Production setting
},
});
NodeApp Type
The returned app instance extends the core App<S> with Node-specific properties:
The underlying Node.js backend instance.
True when NO_COLOR environment variable is present.
hotReload
HotStateReloadController | null
Hot reload controller when configured, null otherwise.
createNodeBackend
Low-level backend constructor. Prefer createNodeApp() for standard usage.
import { createNodeBackend } from "@rezi-ui/node" ;
import { createApp } from "@rezi-ui/core" ;
const backend = createNodeBackend ({
executionMode: "worker" ,
fpsCap: 60 ,
});
const app = createApp ({
backend ,
initialState: {},
});
Hot State Reload
Development feature for hot-reloading view and route modules without losing state.
Configuration
import { createNodeApp } from "@rezi-ui/node" ;
import { watch } from "node:fs" ;
const app = createNodeApp ({
initialState: { count: 0 },
hotReload: {
// Watch view file
view: {
path: "./src/view.ts" ,
exportName: "view" , // Named export to reload
},
// Optional: Watch routes
routes: {
path: "./src/routes.ts" ,
exportName: "routes" ,
},
// Optional: Custom file watcher
watcher : ( paths , onChange ) => {
// Custom watch implementation
return () => {}; // Cleanup
},
},
});
await app . run ();
// HSR automatically starts/stops with app lifecycle
Manual Control
import { createHotStateReload } from "@rezi-ui/node" ;
const hsr = createHotStateReload ( app , {
view: { path: "./src/view.ts" , exportName: "view" },
});
await hsr . start ();
// ... app runs with HSR active
await hsr . stop ();
Start watching for file changes.
Stop watching and cleanup.
Manually trigger a reload.
Image Loading
Load image from file system or URL for use in ui.image().
import { createNodeApp , loadImage } from "@rezi-ui/node" ;
import { ui } from "@rezi-ui/core" ;
const app = createNodeApp ({ initialState: {} });
app . view ( async () => {
const logo = await loadImage ( "./logo.png" );
return ui . page ({ p: 1 }, [
ui . image ({
data: logo . data ,
width: logo . width ,
height: logo . height ,
fit: "contain" ,
}),
]);
});
Supported formats : PNG, JPEG, WebP, GIF (via image decoding)
Stream Utilities
createNodeTailSource
Create a tail source for useTail hook to follow file updates.
import { createNodeApp , createNodeTailSource } from "@rezi-ui/node" ;
import { defineWidget , useTail , ui } from "@rezi-ui/core" ;
const LogViewer = defineWidget (() => {
const logs = useTail ( ctx , {
source: createNodeTailSource ( "/var/log/app.log" ),
maxLines: 100 ,
});
return ui . column ( logs . lines . map (( line ) => ui . text ( line )));
});
Configuration Options
Execution Modes
worker (default): Engine runs in worker thread for best performance
inline: Engine runs in main thread for easier debugging
Frame Transport
copy (default): Frame data copied to worker
sab: Use SharedArrayBuffer for zero-copy frame submission (experimental)
import { createNodeApp } from "@rezi-ui/node" ;
const app = createNodeApp ({
initialState: {},
config: {
// Frame rate
fpsCap: 30 , // Lower for production apps
// Buffer sizes
maxEventBytes: 8192 , // Event batch buffer size
maxDrawlistBytes: 1024 * 1024 , // Max drawlist size (1MB)
// Worker thread settings (when executionMode: 'worker')
frameSabSlotCount: 2 , // SAB ring buffer slots
frameSabSlotBytes: 512 * 1024 , // Bytes per slot
},
});
NO_COLOR Support
createNodeApp automatically detects the NO_COLOR environment variable and converts any provided theme to monochrome:
# Force monochrome output
NO_COLOR = 1 node dist/main.js
import { createNodeApp } from "@rezi-ui/node" ;
import { draculaTheme } from "@rezi-ui/core" ;
const app = createNodeApp ({
initialState: {},
theme: draculaTheme , // Automatically converted to mono when NO_COLOR=1
});
console . log ( app . isNoColor ); // true when NO_COLOR is set
TypeScript Types
import type {
NodeApp ,
NodeAppConfig ,
NodeBackend ,
NodeBackendConfig ,
CreateNodeAppOptions ,
HotStateReloadController ,
HotStateReloadOptions ,
} from "@rezi-ui/node" ;
Runtime Requirements
Node.js : 18.0.0 or higher
Bun : 1.3.0 or higher
Platform : Linux, macOS, Windows (with limitations)
@rezi-ui/core Core framework APIs
Getting Started Installation guide
App Lifecycle Understanding app lifecycle
Worker Model Backend architecture details