v0.1.0-dev.1177

Ziex

/

The full-stack web framework for Zig.

Compile-time safety, deterministic performance, absolute simplicity, and a delightful developer experience.

$ curl -fsSL https://ziex.dev/install | bash
> powershell -c "irm ziex.dev/install.ps1 | iex"
Ziguana Mascot

Features

Everything you need to build fast, safe, and deployable web applications.

Fast Performance

Significantly faster at SSR than many other frameworks. Optimized for speed and low latency.

Familiar Syntax

Familiar JSX-like syntax, or plain HTML-style markup, with full access to Zig's control flow.

File System Routing

Just put files in folders to create routes. Simple and intuitive structure for any scale.

API Routes

Create API endpoints by adding route.zig files to your project. Native Zig performance.

Hybrid Rendering

Optional client-side rendering for interactive experiences when you need it. SSR by default.

Control Flow

if/else, for/while, and switch all work as expected. It's just Zig syntax.

Developer Tooling

CLI, hot reload, and editor extensions for the best development experience.

Deploy Anywhere

Standalone binaries, Cloudflare, Vercel, or any edge runtime host. Build once, run anywhere.

Predictable Memory

Explicit memory management. No GC pauses, no hidden allocations. Total control over your app's footprint.

Performance

View benchmark →
Each framework runs in a Docker container limited to 2 CPU cores and 2 GB RAM.

Ziex
27k
FrameworkZiex
Requests/sec27,736
P50 Latency1.46 ms
P99 Latency7.33 ms
7.3k
FrameworkLeptos
Requests/sec7,272
P50 Latency5.75 ms
P99 Latency21.75 ms
6.2k
FrameworkDioxus
Requests/sec6,164
P50 Latency3.91 ms
P99 Latency48.40 ms
2.3k
FrameworkJetzig
Requests/sec2,268
P50 Latency12.86 ms
P99 Latency98.69 ms
1.7k
FrameworkSolidStart
Requests/sec1,670
P50 Latency26.94 ms
P99 Latency78.81 ms
281
FrameworkNext.js
Requests/sec281
P50 Latency173.99 ms
P99 Latency324.59 ms
Dockerized SSR endpoint hit with 2k requests at 20 concurrent connections, averaged over 2 runs.
Ziex
38.1%
FrameworkZiex
Avg CPU38.1%
Peak CPU92.1%
Requests/sec27,736
56.7%
FrameworkLeptos
Avg CPU56.7%
Peak CPU90.8%
Requests/sec7,272
60.6%
FrameworkSolidStart
Avg CPU60.6%
Peak CPU89.1%
Requests/sec1,670
63.5%
FrameworkDioxus
Avg CPU63.5%
Peak CPU96.4%
Requests/sec6,164
68.3%
FrameworkNext.js
Avg CPU68.3%
Peak CPU90.7%
Requests/sec281
79.8%
FrameworkJetzig
Avg CPU79.8%
Peak CPU100.6%
Requests/sec2,268
Average CPU utilization during the load test via cgroup cpu.stat. Hover for peak CPU.
6.8 MB
FrameworkLeptos
Idle Memory1.6 MB
Peak Memory6.8 MB
8.7 MB
FrameworkDioxus
Idle Memory1.9 MB
Peak Memory8.7 MB
16.7 MB
FrameworkJetzig
Idle Memory8.3 MB
Peak Memory16.7 MB
Ziex
19.1 MB
FrameworkZiex
Idle Memory13.4 MB
Peak Memory19.1 MB
150.9 MB
FrameworkSolidStart
Idle Memory30.7 MB
Peak Memory150.9 MB
263.4 MB
FrameworkNext.js
Idle Memory77.9 MB
Peak Memory263.4 MB
Peak container RSS during load test. Lower is better. Hover for idle memory.
246 ms
FrameworkLeptos
Cold Start246 ms
Image Size24 MB
265 ms
FrameworkDioxus
Cold Start265 ms
Image Size93 MB
Ziex
270 ms
FrameworkZiex
Cold Start270 ms
Image Size25 MB
275 ms
FrameworkJetzig
Cold Start275 ms
Image Size67 MB
473 ms
FrameworkSolidStart
Cold Start473 ms
Image Size351 MB
904 ms
FrameworkNext.js
Cold Start904 ms
Image Size275 MB
Time for the container to start and become ready to serve requests. Lower is better.
24 MB
FrameworkLeptos
Image Size24 MB
Binary Size11.1 MB
Ziex
25 MB
FrameworkZiex
Image Size25 MB
Binary Size10.9 MB
67 MB
FrameworkJetzig
Image Size67 MB
Binary Size53.7 MB
93 MB
FrameworkDioxus
Image Size93 MB
Binary SizeN/A
275 MB
FrameworkNext.js
Image Size275 MB
Binary SizeN/A
351 MB
FrameworkSolidStart
Image Size351 MB
Binary SizeN/A
Size of the final Docker image. Smaller images are faster to deploy and use less storage.
Last benchmarked on 2026-06-11View CI run →

Deploy Anywhere.

Ziex compiles to a single, statically linked binary or a WASI module, making it compatible with every major cloud provider and edge network.

Standalone

Deploy as a self-contained binary on Linux, macOS, or Windows. Statically linked with zero runtime dependencies.

Edge Anywhere

Deploy to the edge via WASI. Native support for Cloudflare and Vercel.

Static

Generate a statically pre-rendered site at build time. Deploy to GitHub Pages, Netlify, S3, or any CDN.

Cross-Platform

Build for any target from any host. Easily cross-compile optimized binaries for x86_64, aarch64, and more.

Code Examples

Short, focused snippets that show how each feature feels in practice.

Control Flow
const ControlIfProps = struct { is_admin: bool };
pub fn ControlIf(
    allocator: zx.Allocator,
    props: ControlIfProps,
) zx.Component {
    return (
        <div @{allocator}>
            {if (props.is_admin) (
                <span>Admin</span>
            ) else (
                <span>Member</span>
            )}
        </div>
    );
}
pub fn ControlIfOptional(allocator: zx.Allocator) zx.Component {
    const maybe_name: ?[]const u8 = "Zig";
    return (
        <div @{allocator}>
            {if (maybe_name) |name| (<span>{name}</span>)}
        </div>
    );
}
pub fn ControlIfError(allocator: zx.Allocator) zx.Component {
    const parsed =
        std.fmt.parseInt(u32, "42", 10);

    return (
        <div @{allocator}>
            {if (parsed) |value| (
                <span>{value}</span>
            ) else |err| (
                <span>{@errorName(err)}</span>
            )}
        </div>
    );
}
pub fn ControlWhile(allocator: zx.Allocator) zx.Component {
    var i: usize = 0;
    return (
        <ul @{allocator}>
            {while (i < 3) : (i += 1) (<li>Item {i + 1}</li>)}
        </ul>
    );
}
pub fn ControlWhileOptional(allocator: zx.Allocator) zx.Component {
    var maybe: ?u32 = 1;
    return (
        <ul @{allocator}>
            {while (maybe) |value| : (maybe = if (value < 3) value + 1 else null) (
                <li>{value}</li>
            )}
        </ul>
    );
}
pub fn ControlWhileError(allocator: zx.Allocator) zx.Component {
    var first: bool = true;
    return (
        <div @{allocator}>
            {while (parseOnce(&first)) |value| (
                <span>{value}</span>
            ) else |err| (
                <span>{@errorName(err)}</span>
            )}
        </div>
    );
}

fn parseOnce(first: *bool) !u32 {
    if (first.*) {
        first.* = false;
        return 42;
    }
    return error.Done;
}
Caching
pub fn CacheComponent(
    allocator: zx.Allocator,
) !zx.Component {
    return (<Slow @{allocator} @caching="10s" />);
}

fn Slow(allocator: zx.Allocator) !zx.Component {
    try std.Io
        .sleep(zx.io(), .fromNanoseconds(2000000000), .awake);
    return (<div @{allocator}>Slow</div>);
}
pub fn Page(
    ctx: zx.PageContext,
) !zx.Component {
    try std.Io
        .sleep(zx.io(), .fromNanoseconds(2000000000), .awake);
    return (
        <div @allocator={ctx.arena}>
            <h1>Expensive Page</h1>
            <p>I take too long to load.</p>
        </div>
    );
}

pub const options = zx.PageOptions{
    .caching = .{ .seconds = 300 },
};
File System Routing
pub fn Page(
    ctx: zx.PageContext,
) zx.Component {
    return (
        <div @allocator={ctx.arena}>
            <h1>Home</h1>
        </div>
    );
}
pub fn Layout(
    ctx: zx.LayoutContext,
    children: zx.Component,
) zx.Component {
    return (
        <html @allocator={ctx.arena}>
            <body>
                {children}
            </body>
        </html>
    );
}
Components
const ButtonProps = struct { label: []const u8 };
pub fn Button(
    ctx: *zx.ComponentCtx(ButtonProps),
) zx.Component {
    return (
        <button @allocator={ctx.allocator}>
            Click {ctx.props.label}
        </button>
    );
}
pub fn Fragment(
    allocator: zx.Allocator,
) zx.Component {
    return (
        <fragment @{allocator}>
            <span>One</span>
            <>
                <p>Two</p><p>Three</p>
            </>
        </fragment>
    );
}
pub fn SpreadProps(
    allocator: zx.Allocator,
) zx.Component {
    const attrs =
        .{ .class = "btn", .id = "cta" };
    const class = "primary";
    return (
        <section @{allocator}>
            <button {..attrs}>Spreading</button>
            <button {class}>Shorthand</button>
        </section>
    );
}
pub fn DynamicAttr(
    allocator: zx.Allocator,
) zx.Component {
    const is_active = true;
    const class = if (is_active) "active" else "idle";
    const color = if (is_active) "green" else "red";
    return (
        <section @{allocator}>
            <button class={class}>Go</button>
            <button style=`color: {color};`>
                Template String
            </button>
        </section>
    );
}
Dynamic Path
pages/[id]/page.zx
pub fn Page(ctx: zx.PageContext) zx.Component {
    const id = ctx.request.params.get("id");
    return (
        <section @allocator={ctx.arena}>
            <h1>User {id}</h1>
        </section>
    );
}
API Route
route.zig
pub fn PUT(ctx: zx.RouteContext) !void {
    try ctx.response.json(.{ .status = "ok" });
}

pub fn POST(ctx: zx.RouteContext) !void {
    const Data = struct { id: u32 };
    const data =
        try ctx.request.json(Data, .{});

    try ctx.response.json(.{
        .id = data.?.id,
        .created = true,
    });
}
WebSocket
routes/ws/route.zig
pub fn GET(ctx: zx.RouteContext) !void {
    try ctx.socket.upgrade({});
}

pub fn Socket(ctx: zx.SocketContext) !void {
    try ctx.socket.write(
        try ctx.fmt("{s}", .{ctx.message}),
    );
}

pub fn SocketOpen(ctx: zx.SocketOpenContext) !void {
    try ctx.socket.write("Opened!");
}
Client-side Rendering
counter.zx
pub fn Client(allocator: zx.Allocator) zx.Component {
    return (<Counter @{allocator} @rendering={.client} />);
}
pub fn Counter(ctx: *zx.ComponentCtx(void)) zx.Component {
    const count = ctx.state(i32, 0);
    return (
        <div @allocator={ctx.allocator} class="counter">
            <button onclick={ctx.bind(increment)}>
                Click Me: {count}
            </button>
        </div>
    );
}
fn increment(e: *zx.client.Event.Stateful) void {
    const count = e.state(i32);
    count.set(count.get() + 1);
}
Preview