Back to Linux guides

Zero-Native: Tiny Desktop Apps with Zig, System WebView, and Direct C Interop

Stanley Ulili
Updated on May 17, 2026

Zero-Native is a desktop and mobile application framework built in Zig. The native shell is minimal: it creates a window, hosts a WebView, and provides a bridge between the web UI and native OS APIs. By using the operating system's built-in WebView (WKWebView on macOS, WebView2 on Windows) rather than bundling Chromium, it produces distributable binaries in the single-digit megabyte range. Chromium can be included via the Chromium Embedded Framework when cross-platform rendering consistency is required.

Zero-Native documentation screenshot highlighting its core benefits: Tiny and fast, choose your web engine, and fast native rebuilds

Why Zig for the native layer

Zig's @cImport feature allows direct inclusion of C header files without binding generators or wrapper code. Any C library or OS API is one import away. This makes the native shell straightforward to extend: adding a native capability means writing Zig that calls a C API, not navigating an FFI abstraction layer.

Zig is also simpler than Rust for this use case. There is no borrow checker or lifetime management system. Memory management is manual, which shifts responsibility to the developer, but reduces the conceptual overhead for those coming from higher-level languages.

Architecture comparison: Zero-Native vs. Electrobun

Both Zero-Native and Electrobun aim to be lightweight Electron alternatives, but their architectures differ meaningfully.

Hand-drawn diagram comparing the architectural stacks of Electrobun and Zero-Native showing different layers of abstraction

Electrobun runs its main process logic in TypeScript inside a Bun web worker. Native OS calls go through Bun's Foreign Function Interface (FFI) into C++/Objective-C code. The path is: TypeScript → Bun runtime (FFI) → C++/Objective-C → OS API.

Zero-Native has no intermediate JavaScript runtime for the main process. The Zig binary is the main process. Native OS calls go directly from Zig to system APIs via @cImport. The path is: Zig → OS API.

Fewer abstraction layers means a smaller binary, less overhead per native call, and a simpler mental model for the native side of the application.

Setup

Prerequisites

Zig is required. On macOS with Homebrew:

 
brew install zig

Verify:

 
zig version

Install the Zero-Native CLI following the instructions on the Zero-Native website. Once installed, zero-native should be available in your PATH.

Scaffolding a project

 
zero-native init demo-proj --frontend react

The zero-native init command being typed into the terminal with the project name and --frontend flag

--frontend react sets up a Vite + React frontend. Other options include vue, svelte, next, and vite for a vanilla template.

The generated project structure:

Terminal output listing the files generated by init: app.zon, assets, build.zig, frontend, src

  • app.zon: application configuration in Zig Object Notation
  • assets/: static assets including application icons
  • build.zig: Zig build script defining compilation, linking, and packaging
  • frontend/: Vite project for the web UI
  • src/: Zig source for the native shell

Running the application

 
zig build run

This installs frontend dependencies, builds the frontend for production, compiles the Zig shell, and launches the application.

Default "Demo Project" application window showing a simple UI with "native bridge" and "available" text

Development server with HMR

For active development, the dev server compiles a debug binary and starts the Vite dev server. Changes to frontend/src/ are reflected instantly via HMR without restarting the application.

 
zig build dev

Configuration: app.zon

app.zon controls application metadata and behavior. Key settings:

 
.{
    .id = "dev.zero_native.demo-proj",
    .name = "demo-proj",
    .display_name = "Demo Proj",
    .version = "0.1.0",
    .icons = .{ "assets/icon.icns" },
    .platforms = .{ "macos", "linux" },
    .capabilities = .{ "webview" },
    .web_engine = "system",
    .windows = .{
        .{
            .label = "main",
            .title = "Demo Proj",
            .width = 720,
            .height = 480,
        },
    },
}

.web_engine accepts "system" (default, uses the OS WebView, smallest binary) or "chromium" (bundles CEF, larger binary, consistent rendering across platforms).

Packaging

 
zig build package

Output goes to zig-out/package/. With the system WebView option, the distributable .app bundle in the demonstration was 2.9 MB. Some community projects have produced builds under 680 KB.

macOS Finder window showing the packaged application with the size column displaying 2.9 MB

Tradeoffs

Zero-Native requires writing Zig to extend the native layer. For developers unfamiliar with systems programming, this is an additional learning investment beyond the web UI work.

The project is relatively early-stage compared to Electron or Electrobun. The feature set and ecosystem are less mature. Using the system WebView means rendering behavior varies between platforms unless CEF is included.

For applications where any of these constraints matter, Zero-Native's tiny binary size and direct architecture are the primary reasons to accept them.

Final thoughts

Zero-Native is the right choice when binary size, startup speed, and native performance are priorities and the team is willing to write a small amount of Zig for native integrations. The @cImport capability makes adding C-based native libraries straightforward, and the direct Zig-to-OS architecture avoids the overhead that accumulates in FFI-layered frameworks.

Documentation and installation instructions are at zero-native.dev.

Got an article suggestion? Let us know
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.