Skip to Content

Tynd

Desktop apps in TypeScript. One language, native binary, no glue code.

Tynd is a desktop-app framework with a TypeScript backend and a native WebView front-end. Your frontend and backend are both TypeScript. RPC types flow from typeof backend — no codegen, no IDL, no schema file. Build produces a small self-contained binary: ~6.5 MB for the lite runtime, ~44 MB for full (Bun packed).

bunx @tynd/cli create my-app

New here? Start with the 5-minute quickstart — scaffold an app, run it with HMR, ship a binary.

At a glance

  • TypeScript top to bottom. Backend, frontend, IPC, config — same language, no codegen.
  • Two runtime modes, one API. Start with lite (~6.5 MB binary, embedded QuickJS). Switch to full with one config line when you need Bun’s JIT or native npm bindings.
  • Native window, zero network. No HTTP server, no loopback TCP port, no firewall prompt. Frontend and IPC ride a native custom scheme.
  • 26 OS APIs, identical in both modesfs, sql, http, websocket, terminal (real PTY), compute, dialog, tray, menu, notification, clipboard, shell, process, sidecar, singleInstance, shortcuts, keyring, autolaunch, store, updater, workers, app, os, path, tyndWindow, plus typed emitters and streaming RPC.
  • Zero-copy binary IPC. Multi-MB payloads skip JSON/base64 — ArrayBuffer end-to-end, 5-10× faster than the usual webview-framework binary path.
  • First-class installers. .app, .dmg, .deb, .rpm, .AppImage, NSIS, MSI. Build tools auto-download on first build. Built-in code signing + macOS notarization.
  • Framework-agnostic. React, Vue, Svelte, Solid, Preact, Lit, Angular — anything that outputs a pure SPA.

Why Tynd

Most desktop-app frameworks force you to pick a language for the native side (Rust for Tauri, Go for Wails, or the entire Chromium for Electron). Tynd keeps the native layer invisible: you write TypeScript, you get a native binary.

How it works

TypeScript backend Native OS window ────────────────────────── ───────────────────────── export async function greet() ◄── IPC ─ await api.greet("Alice") events.emit("ready", payload) ─── push ─► api.on("ready", handler) tynd-full — your TypeScript runs on Bun, wrapped in a native host tynd-lite — your TypeScript runs inside the native host, no extra runtime

Frontend assets and IPC ride a native custom scheme — no HTTP server, no loopback port, no firewall prompt. Multi-MB binary payloads (fs.readBinary, fs.writeBinary, compute.hash) skip JSON entirely via a dedicated binary channel.

Two runtime modes

litefull
JS runtimeembedded QuickJS — ships inside the native binaryBun, packed into the native binary
Hot JS speedinterpreter — fine for IPC glue, slower on tight loopsBun JIT — often 10-100× faster on CPU-bound JS
IPC overheadin-process, no serialization hopone serialization hop (OS pipe)
Tynd OS APIs (fs, http, sql, …)
Web-standard globals (fetch, WebSocket, crypto.subtle)✓ polyfilled✓ native
JS-level Bun.* / node:*
npm with native bindings
Binary sizesmaller (~6.5 MB)larger (~44 MB, Bun compressed)
Startupfaster (everything in-process)slower (spawns Bun)

See Runtimes for the full parity table.

Requirements

Bun  is required for app developers. Tynd is a Bun-first framework — the CLI, the dev server, and the full runtime all run on Bun. Node.js is not supported as a replacement.

# macOS / Linux curl -fsSL https://bun.sh/install | bash # Windows (PowerShell) powershell -c "irm bun.sh/install.ps1 | iex"

End users of your built app need nothing — whichever runtime you shipped is already packed into the distributed binary.

Last updated on