If you’ve ever built a desktop or modern full-stack web app using frameworks like Tauri or Wails, you know how brilliant the webview architecture is. Combining a lightweight OS webview with a fast backend language like Rust or Go beats shipping a bloated 150MB Electron runtime any day.
I love these tools and still build applications with them. But as an engineer, I started wondering what it would look like if we pushed the boundaries a step further. What if we could completely eliminate the multi-language context switch, throw away the heavy Node build toolchains, and build everything inside a single, unified systems language?
Enter Zig (and a wild idea)
Over the past six months, I’ve been diving deep into Zig. Coming from a background with plenty of Go, I completely fell in love with Zig's philosophy: extreme simplicity, no hidden control flow, no macros, a "standard library first" mindset, and a powerful build system that replaces messy Makefiles and CMake entirely.
With the recent async/IO overhauls in Zig 0.16.0 (std.io updates and native io_uring support), it felt like the absolute perfect time to see just how far the envelope could be pushed.
I looked at the current ecosystem and realized something was missing: A pure, unified, single-language framework for both web and desktop apps.
So, I decided to go on a bit of an adventure and build it. I call it Verve.
What exactly is Verve?
Verve is a full-stack, pure-Zig framework for building high-performance web and native desktop applications.
If you want to see the architecture in action right now, you can dive straight into the Official Documentation at verveframework.dev!
There is no Node.js toolchain, no virtual DOM, and no macros. Everything compiles down into a single, highly optimized binary. You run zig build, and you get your server or your native desktop application. Simple as that.
Here is a quick look at the architectural choices powering the project:
1. Unified Language, Unified Codebase
Instead of splitting your brain between Go/Rust for the backend and TS/JS for the frontend, your entire application UI and logic is written in pure Zig.
- Web: The server renders HTML via native Zig functions.
- Client Interactivity: Interactive components are written in Zig and compiled directly to WASM chunks using Zig's native WebAssembly compilation target.
2. Islands Architecture & Fine-Grained Reactivity
Verve takes inspiration from modern web frameworks but implements them natively. Pages are Server-Side Rendered (SSR) first, meaning every page is fully formed HTML that functions perfectly even if JavaScript is entirely disabled.
When you need interactivity, you opt into an Island:
- The build system automatically code-splits every island into its own separate WebAssembly (
.wasm) chunk. - Chunks are lazy-loaded on-demand and hydrated with typed properties.
- It uses a fine-grained reactive graph (Signals and Effects) shared seamlessly between the server and the WASM client. Updates touch exactly the DOM nodes that change—no heavy Virtual DOM diffing required.
// A simple reactive route in Verve
const verve = @import("verve");
pub const routes: []const verve.Route = &.{
verve.Route.init("/", renderHome),
verve.Route.init("/hello/:name", renderHello),
};
fn renderHello(ctx: *verve.Context) !*verve.Node {
const name = ctx.param("name") orelse "world";
return ctx.div().class("card").children(.{
ctx.h1("Hello"),
ctx.p().children(.{
ctx.span().text("Greetings, "),
ctx.code(name),
}),
}).build();
}
3. Native Desktop
For desktop applications, Verve embeds the OS’s native webview window (WKWebView on macOS, WebView2 on Windows, and WebKitGTK on Linux).
Unlike other webview solutions, Verve sets up a highly secure verve://app/ asset scheme. Assets are embedded directly inside the binary as an AssetEntry table at compile time. Frontend modules communicate with your Zig backend through a deeply typed IPC bridge with strict compile-time route generation. No open local ports, no localhost footprint.
4. Zero JavaScript Toolchain (Yes, Really)
One of my primary goals was to completely strip away the complex web infrastructure. Because Zig's build system is incredibly robust, it acts as your compiler, linker, asset packager, and WASM orchestrator all at once. You don’t need npm, bun, vite, or esbuild.
Now, to be totally fair, browsers don't speak native Zig—so there is a tiny piece of JavaScript glue involved under the hood called verve.js. But here's the magic: you don't install it, build it, or manage it. The framework automatically serves it as a minimal, lightweight bridge at /verve.js. It handles mounting your compiled WASM islands, passing typed properties, and letting the client runtime talk back to your backend.
You just run zig build, and the framework orchestrates the entire puzzle for you.
Moving Beyond Tauri and Wails
Don't get me wrong: I still build applications using both Tauri and Wails, and they are phenomenal projects that paved the way for lightweight desktop apps. But I wanted to see what else could be built if we wiped the slate clean.
Verve shifts the paradigm in a few key ways:
-
Instant Compile & Dev Loops: Zig compiles incredibly fast compared to heavy macro-centric Rust code. With
dev_assetsconfigured, you can edit your frontend markup and live-reload instantly without rebuilding the binary backend. - Single Mental Model: You don't have to think about data-serialization boundaries between Go/Rust types and TypeScript interfaces. Everything uses native Zig structs. Comptime-generated, typed client stubs handle data transfers natively.
-
Batteries Included (Natively): Verve isn't just a webview router. It includes full server-side visualization capabilities (
verve.vizrenders everything from force-directed layouts to complex charts directly to server-side SVG), a declarative tween/timeline animation engine, and hardware-accelerated WebGL2/WebGPU 3D scenes out of the box.
The Journey So Far
Learning Zig over the last half-year has completely changed how I think about systems programming. Coming from Go, I missed the simplicity when dealing with complex Rust syntax or C-bindings. Zig gives you that exact same readability and predictability, but with absolute control over memory management and allocators (using explicit arenas per request context to completely eliminate leaks).
Verve is the result of taking that systems-level power and applying it directly to application developer productivity.
Now, I wish I could take all the credit and claim I built this entirely solo, but I have to give a massive shoutout to my friend Claude Code for the major assist along the way! 🤖
Give it a spin!
If you want to escape the massive Node ecosystem, skip the multi-minute compile times, and write lightning-fast full-stack web or desktop apps using a beautiful, modern language, come join the adventure.
Getting started is as simple as cloning the repo and executing your native toolchain:
git clone https://github.com/sirhco/verve
cd verve
zig build
I’d love to hear your thoughts, feedback, or any issues you encounter as you play around with it! Check out the GitHub repository, drop a star if you like the direction, and let me know what you think in the comments below!
Top comments (0)