Murasaki
Core Concepts

Architecture

How the Rust host, local Node runtime, and WebView renderer fit together.

Murasaki is a three-layer desktop runtime. React renders in the operating system WebView, application backend code runs in a bundled Node.js process, and a small Rust host owns the native window and application lifecycle.

Native application
01 · native hostRust · tao / wry / muda

Windows, WebViews, native menus, lifecycle, and update handoff

launches & supervises
02 · application backendLocal Node runtime

src/main.ts · use-main · use-server · API routes

authenticated loopback HTTP
03 · rendererOS WebView

React 19 · Murasaki router · your renderer code

This is deliberately different from Electron's embedded Chromium + Node renderer model. Renderer code does not receive Node globals. Put filesystem, database, socket, worker, and secret-bearing code in src/main.ts, a 'use main' module, a 'use server' action, or an src/api/ route.

Layer responsibilities

LayerOwnsDoes not own
Rust hostNative event loop, configured window template catalog, per-window navigation/capability policy, OS open-request normalization, menus, Node child supervision, final update handoffBusiness logic and React state
Local Node runtimeLong-lived main lifecycle, create/destroy of configured secondary templates, registered URL/file handling, actions, API routes, update verification, application resources and dataArbitrary URLs or runtime capability policies for native windows
RendererUI, routing, browser APIs, typed backend calls, permitted management of declared windowsDirect filesystem/Node/native module access

Murasaki is pre-1.0. Declared windows have independent, deny-by-default command allowlists. URL, filesystem path, target-window, and OS-permission arguments support explicit allow/deny scopes; other command arguments remain command-level. Packaged macOS/Windows apps enforce a single instance, can register URL schemes and file associations, and expose matching activations to Node Main through openRequested(). Check Platform & feature status before committing a production architecture to a feature.

Development and packaged runtime

The application code keeps the same boundaries in both modes, but the host processes differ:

murasaki devPackaged app
Web assetsVite dev server with HMRdist/client served by bundled Node
Node backendVite child processPortable Node runtime inside app resources
Native hostCLI process loads @murasakijs/nativeStandalone Rust launcher
Declared windowsFull template catalog passed to the native host; only createOnLaunch templates start immediatelyFull catalog loaded from bundle metadata; only createOnLaunch templates start immediately
Main entryLoaded with Vite SSR; exact entry hot-reloadsCompiled to server/main.mjs
Backend callsVite middlewareBundled loopback HTTP server
URL/file registrationNot installed by dev modemacOS app metadata or Windows installer registry

Production begins with a deterministic loopback port derived from appId and persists the port that actually binds. If another application already owns the first choice, the bundled server selects a bounded fallback and reuses it on later launches. This keeps the renderer origin stable without making unrelated hash-colliding apps mutually exclusive. Keep appId stable after release: changing it can change application data paths, browser profiles, bundle identity, the single-instance lock, and the local origin.

Each window label owns a distinct WebContext. Service Workers, SharedWorkers, cookies, and Web Storage from a secondary window therefore cannot observe the primary window's authenticated backend traffic. Recreating the same label reuses its context within the process; persistent profile behavior across launches is platform-dependent. On macOS 11–13, secondary labels use isolated non-persistent stores because custom persistent stores require macOS 14. webview.incognito: true makes every label non-persistent.

Next.js-like, not Next.js itself

Murasaki adopts familiar conventions—src/app, layouts, route handlers, directives, and React 19—but it is not the Next.js runtime. There are no React Server Components or Edge runtime, and middleware only participates in client navigation. Each guide documents the supported subset; do not assume an API is available because it exists in Next.js.

Next

Improve this page on GitHub

On this page