v0.1.0-dev.1227

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
13k
FrameworkZiex
Requests/sec13,882
P50 Latency1.44 ms
P99 Latency19.67 ms
9.4k
FrameworkLeptos
Requests/sec9,446
P50 Latency2.63 ms
P99 Latency8.16 ms
6.1k
FrameworkDioxus
Requests/sec6,94
P50 Latency1.38 ms
P99 Latency43.80 ms
2.9k
FrameworkJetzig
Requests/sec2,926
P50 Latency7.41 ms
P99 Latency48.45 ms
1.5k
FrameworkSolidStart
Requests/sec1,464
P50 Latency16.43 ms
P99 Latency77.06 ms
264
FrameworkNext.js
Requests/sec264
P50 Latency105.62 ms
P99 Latency286.70 ms
Dockerized SSR endpoint hit with 3000 requests at 30 concurrent connections, averaged over 3 runs.
Ziex
26.5%
FrameworkZiex
Avg CPU26.5%
Peak CPU77.6%
Requests/sec13,882
34.1%
FrameworkLeptos
Avg CPU34.1%
Peak CPU89.1%
Requests/sec9,446
37.9%
FrameworkDioxus
Avg CPU37.9%
Peak CPU80.1%
Requests/sec6,94
57.5%
FrameworkSolidStart
Avg CPU57.5%
Peak CPU82.7%
Requests/sec1,464
59.6%
FrameworkJetzig
Avg CPU59.6%
Peak CPU99.5%
Requests/sec2,926
68.9%
FrameworkNext.js
Avg CPU68.9%
Peak CPU88.5%
Requests/sec264
Average CPU utilization during the load test via cgroup cpu.stat. Hover for peak CPU.
6.9 MB
FrameworkLeptos
Idle Memory1.8 MB
Peak Memory6.9 MB
7.2 MB
FrameworkDioxus
Idle Memory1.7 MB
Peak Memory7.2 MB
9.3 MB
FrameworkJetzig
Idle Memory6.6 MB
Peak Memory9.3 MB
Ziex
19.9 MB
FrameworkZiex
Idle Memory13.2 MB
Peak Memory19.9 MB
138.6 MB
FrameworkSolidStart
Idle Memory30.5 MB
Peak Memory138.6 MB
246.4 MB
FrameworkNext.js
Idle Memory77.6 MB
Peak Memory246.4 MB
Peak container RSS during load test. Lower is better. Hover for idle memory.
261 ms
FrameworkLeptos
Cold Start261 ms
Image Size24 MB
267 ms
FrameworkDioxus
Cold Start267 ms
Image Size94 MB
272 ms
FrameworkJetzig
Cold Start272 ms
Image Size67 MB
Ziex
275 ms
FrameworkZiex
Cold Start275 ms
Image Size24 MB
454 ms
FrameworkSolidStart
Cold Start454 ms
Image Size351 MB
860 ms
FrameworkNext.js
Cold Start860 ms
Image Size275 MB
Time for the container to start and become ready to serve requests. Lower is better.
Ziex
24 MB
FrameworkZiex
Image Size24 MB
Binary Size9.6 MB
24 MB
FrameworkLeptos
Image Size24 MB
Binary Size10.9 MB
67 MB
FrameworkJetzig
Image Size67 MB
Binary Size53.7 MB
94 MB
FrameworkDioxus
Image Size94 MB
Binary Size9.5 MB
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-12View 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