const features = [_]Feature{ .{ .icon_fn = icons.Lightning, .title = "Fast Performance", .description = "Significantly faster at SSR than many other frameworks. Optimized for speed and low latency." }, .{ .icon_fn = icons.Code, .title = "Familiar Syntax", .description = "Familiar plain HTML-style markup, with full access to Zig's control flow." }, .{ .icon_fn = icons.Folder, .title = "File System Routing", .description = "Just files in folders to create routes." }, .{ .icon_fn = icons.Server, .title = "API Routes", .description = "Create API endpoints by adding route.zig files to your project." }, .{ .icon_fn = icons.Monitor, .title = "Hybrid Rendering", .description = "Client-side rendering for interactive experiences when you need it." }, .{ .icon_fn = icons.Flow, .title = "Control Flow", .description = "if/else, for/while, and switch all work as expected. It's just Zig syntax." }, .{ .icon_fn = icons.Wrench, .title = "Developer Tooling", .description = "CLI, hot reload, and editor extensions for the best development experience." }, .{ .icon_fn = icons.Rocket, .title = "Deploy Anywhere", .description = "Standalone binaries, Cloudflare, Vercel, or any edge runtime host. Build once, run anywhere." }, .{ .icon_fn = icons.Layers, .title = "Predictable Memory", .description = "Explicit memory management of Zig, no hidden allocations." }, }; const deployments = [_]Deployment{ .{ .icon_fn = icons.Terminal, .title = "Standalone", .description = "Deploy as a self-contained binary on Linux, macOS, Windows andy many more platforms that Zig supports." }, .{ .icon_fn = icons.Globe, .title = "Edge Anywhere", .description = "Deploy to the edge via WASI. Native bindings for Cloudflare and Vercel." }, .{ .icon_fn = icons.Layers, .title = "Static", .description = "Generate a statically pre-rendered site at build time. Deploy to GitHub Pages, Netlify, S3, or any CDN." }, .{ .icon_fn = icons.Package, .title = "Cross-Platform", .description = "Build for any target from any host. Easily cross-compile optimized binaries for x86_64, aarch64, and more." }, }; const benchmark_cwv_rows = [_]BenchmarkRow{ .{ .label = "Ziex", .value = 98, .display = "98%", .url = "" }, .{ .label = "Next.js", .value = 44, .display = "44%", .url = "https://nextjs.org" }, .{ .label = "Nuxt", .value = 42, .display = "42%", .url = "https://nuxt.com" }, .{ .label = "Leptos", .value = 27, .display = "27%", .url = "https://leptos.dev" }, }; const bench_data = @import("bench.zon"); const benchfig = @import("benchfig.zon"); const bench_run = bench_data.run; const bench_results = bench_data.results; const bench_len = @typeInfo(@TypeOf(bench_results)).@"struct".field_types.len; fn getFrameworkUrl(comptime id: []const u8) []const u8 { if (std.mem.eql(u8, id, "jetzig")) return "https://jetzig.dev"; if (std.mem.eql(u8, id, "leptos")) return "https://leptos.dev"; if (std.mem.eql(u8, id, "solidjs")) return "https://start.solidjs.com"; if (std.mem.eql(u8, id, "dioxus")) return "https://dioxuslabs.com"; if (std.mem.eql(u8, id, "nextjs")) return "https://nextjs.org"; return ""; } fn sortRows(rows: []BenchmarkRow, comptime lower_is_better: bool) void { std.sort.insertion(BenchmarkRow, rows, {}, struct { fn lessThan(_: void, a: BenchmarkRow, b: BenchmarkRow) bool { return if (lower_is_better) a.value < b.value else a.value > b.value; } }.lessThan); } fn buildSsrRows() [bench_len]BenchmarkRow { @setEvalBranchQuota(10000); var rows: [bench_len]BenchmarkRow = undefined; const field_names = @typeInfo(@TypeOf(bench_results)).@"struct".field_names; inline for (field_names, 0..) |field_name, i| { const d = @field(bench_results, field_name); rows[i] = .{ .label = d.label, .value = d.requests_per_sec, .display = util.formatLargeNumber(d.requests_per_sec), .url = getFrameworkUrl(d.id), .tooltip_metrics = &[_]TooltipMetric{ .{ .label = "Framework", .value = d.label }, .{ .label = "Requests/sec", .value = util.formatRequests(d.requests_per_sec) }, .{ .label = "P50 Latency", .value = util.formatLatency(d.p50_latency_ms) }, .{ .label = "P99 Latency", .value = util.formatLatency(d.p99_latency_ms) }, }, }; } sortRows(&rows, false); return rows; } fn buildMemoryRows() [bench_len]BenchmarkRow { @setEvalBranchQuota(10000); var rows: [bench_len]BenchmarkRow = undefined; const field_names = @typeInfo(@TypeOf(bench_results)).@"struct".field_names; inline for (field_names, 0..) |field_name, i| { const d = @field(bench_results, field_name); rows[i] = .{ .label = d.label, .value = d.peak_memory_mb, .display = util.formatMemory(d.peak_memory_mb), .url = getFrameworkUrl(d.id), .tooltip_metrics = &[_]TooltipMetric{ .{ .label = "Framework", .value = d.label }, .{ .label = "Idle Memory", .value = util.formatMemory(d.idle_memory_mb) }, .{ .label = "Peak Memory", .value = util.formatMemory(d.peak_memory_mb) }, }, }; } sortRows(&rows, true); return rows; } fn buildBuildTimeRows() [bench_len]BenchmarkRow { @setEvalBranchQuota(10000); var rows: [bench_len]BenchmarkRow = undefined; const field_names = @typeInfo(@TypeOf(bench_results)).@"struct".field_names; inline for (field_names, 0..) |field_name, i| { const d = @field(bench_results, field_name); rows[i] = .{ .label = d.label, .value = d.build_time_s, .display = util.formatBuildTime(d.build_time_s), .url = getFrameworkUrl(d.id), .tooltip_metrics = &[_]TooltipMetric{ .{ .label = "Framework", .value = d.label }, .{ .label = "Build Time", .value = util.formatBuildTime(d.build_time_s) }, }, }; } sortRows(&rows, true); return rows; } fn buildColdStartRows() [bench_len]BenchmarkRow { @setEvalBranchQuota(10000); var rows: [bench_len]BenchmarkRow = undefined; const field_names = @typeInfo(@TypeOf(bench_results)).@"struct".field_names; inline for (field_names, 0..) |field_name, i| { const d = @field(bench_results, field_name); rows[i] = .{ .label = d.label, .value = d.cold_start_ms, .display = util.formatColdStart(d.cold_start_ms), .url = getFrameworkUrl(d.id), .tooltip_metrics = &[_]TooltipMetric{ .{ .label = "Framework", .value = d.label }, .{ .label = "Cold Start", .value = util.formatColdStart(d.cold_start_ms) }, .{ .label = "Image Size", .value = util.formatImageSize(d.image_mb) }, }, }; } sortRows(&rows, true); return rows; } fn buildImageSizeRows() [bench_len]BenchmarkRow { @setEvalBranchQuota(10000); var rows: [bench_len]BenchmarkRow = undefined; const field_names = @typeInfo(@TypeOf(bench_results)).@"struct".field_names; inline for (field_names, 0..) |field_name, i| { const d = @field(bench_results, field_name); rows[i] = .{ .label = d.label, .value = d.image_mb, .display = util.formatImageSize(d.image_mb), .url = getFrameworkUrl(d.id), .tooltip_metrics = &[_]TooltipMetric{ .{ .label = "Framework", .value = d.label }, .{ .label = "Image Size", .value = util.formatImageSize(d.image_mb) }, .{ .label = "Binary Size", .value = util.formatBinarySize(d.binary_mb) }, }, }; } sortRows(&rows, true); return rows; } fn buildCpuUsageRows() [bench_len]BenchmarkRow { @setEvalBranchQuota(10000); var rows: [bench_len]BenchmarkRow = undefined; const field_names = @typeInfo(@TypeOf(bench_results)).@"struct".field_names; inline for (field_names, 0..) |field_name, i| { const d = @field(bench_results, field_name); rows[i] = .{ .label = d.label, .value = d.cpu_avg_pct, .display = util.formatCpuPeak(d.cpu_avg_pct), .url = getFrameworkUrl(d.id), .tooltip_metrics = &[_]TooltipMetric{ .{ .label = "Framework", .value = d.label }, .{ .label = "Avg CPU", .value = util.formatCpuPeak(d.cpu_avg_pct) }, .{ .label = "Peak CPU", .value = util.formatCpuPeak(d.cpu_peak_pct) }, .{ .label = "Requests/sec", .value = util.formatRequests(d.requests_per_sec) }, }, }; } sortRows(&rows, true); return rows; } const benchmark_ssr_rows = buildSsrRows(); const benchmark_memory_rows = buildMemoryRows(); const benchmark_build_time_rows = buildBuildTimeRows(); const benchmark_cold_start_rows = buildColdStartRows(); const benchmark_image_size_rows = buildImageSizeRows(); const benchmark_cpu_usage_rows = buildCpuUsageRows(); const benchmark_tabs = [_]BenchmarkTab{ // .{ // .id = "bench-tab-cwv", // .label = "Core Web Vitals", // .metric = "% of real-world sites with good Core Web Vitals", // .footnote = "Full report. Benchmarked against Next.js and Leptos using real-world Core Web Vitals.", // .rows = benchmark_cwv_rows[0..], // .checked = true, // }, .{ .id = "bench-tab-ssr", .label = "SSR", .metric = "Requests per second (higher is better)", .footnote = std.fmt.comptimePrint( "Dockerized SSR endpoint hit with {d} requests at {d} concurrent connections, averaged over {d} runs.", .{ benchfig.requests, benchfig.concurrency, benchfig.runs, }, ), .rows = benchmark_ssr_rows[0..], .checked = true, }, .{ .id = "bench-tab-cpu", .label = "CPU", .metric = "Average CPU usage during load (lower is better)", .footnote = "Average CPU utilization during the load test via cgroup cpu.stat. Hover for peak CPU.", .rows = benchmark_cpu_usage_rows[0..], .checked = false, .lower_is_better = true, }, .{ .id = "bench-tab-memory", .label = "Memory", .metric = "Peak memory under load (lower is better)", .footnote = "Peak container RSS during load test. Lower is better. Hover for idle memory.", .rows = benchmark_memory_rows[0..], .checked = false, .lower_is_better = true, }, .{ .id = "bench-tab-cold-start", .label = "Cold Start", .metric = "Cold start time in milliseconds (lower is better)", .footnote = "Time for the container to start and become ready to serve requests. Lower is better.", .rows = benchmark_cold_start_rows[0..], .checked = false, .lower_is_better = true, }, .{ .id = "bench-tab-image-size", .label = "Size", .metric = "Docker image size (lower is better)", .footnote = "Size of the final Docker image. Smaller images are faster to deploy and use less storage.", .rows = benchmark_image_size_rows[0..], .checked = false, .lower_is_better = true, }, // TODO: currently it is hard to auto calc build time from inside docker build // .{ // .id = "bench-tab-build", // .label = "Build Time", // .metric = "Docker image build time in seconds (lower is better)", // .footnote = "Time to build each framework's Docker image from scratch on the host machine. Lower is better.", // .rows = benchmark_build_time_rows[0..], // .checked = false, // .lower_is_better = true, // }, }; pub fn Page(ctx: zx.PageContext) zx.Component { const allocator = ctx.arena; const current_year = blk: { const timestamp: i64 = @intCast(@divFloor(std.Io.Timestamp.now(zx.io(), .real).nanoseconds, std.time.ns_per_s)); const seconds_per_year = 365.25 * 24 * 60 * 60; const years_since_epoch = @as(i64, @intFromFloat(@as(f64, @floatFromInt(timestamp)) / seconds_per_year)); break :blk 1970 + years_since_epoch; }; const feature_examples = @embedFile("./examples/feature_examples.zx"); const control_tabs = [_]CodeTab{ .{ .id = "control-tab-if", .label = "If", .section = "Control Flow: if", .code = "", .checked = true }, .{ .id = "control-tab-if-opt", .label = "If Optional", .section = "Control Flow: if optional capture", .code = "", .checked = false }, .{ .id = "control-tab-if-err", .label = "If Error", .section = "Control Flow: if error capture", .code = "", .checked = false }, .{ .id = "control-tab-while", .label = "While", .section = "Control Flow: while", .code = "", .checked = false }, .{ .id = "control-tab-while-opt", .label = "While Optional", .section = "Control Flow: while optional capture", .code = "", .checked = false }, .{ .id = "control-tab-while-err", .label = "While Error", .section = "Control Flow: while error capture", .code = "", .checked = false }, }; const caching_tabs = [_]CodeTab{ .{ .id = "caching-tab-component", .label = "Component", .section = "Caching: component", .code = "", .checked = true }, .{ .id = "caching-tab-page", .label = "Page", .section = "Caching: page", .code = "", .checked = false }, }; const fs_tabs = [_]CodeTab{ .{ .id = "fs-tab-page", .label = "Page", .section = "File System Routing: page", .code = "", .checked = true }, .{ .id = "fs-tab-layout", .label = "Layout", .section = "File System Routing: layout", .code = "", .checked = false }, }; const component_tabs = [_]CodeTab{ .{ .id = "component-tab-basics", .label = "Basics", .section = "Component: basics", .code = "", .checked = true }, .{ .id = "component-tab-frag", .label = "Fragment", .section = "Component: fragment", .code = "", .checked = false }, .{ .id = "component-tab-props", .label = "Props", .section = "Component: props", .code = "", .checked = false }, .{ .id = "component-tab-attr", .label = "Attributes", .section = "Component: attr", .code = "", .checked = false }, }; return (

Ziex

/

Full-stack web framework for Zig.

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

Ziguana Mascot

Features

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

{for (features) |f| ()}
View benchmark →
Each framework runs in a Docker container limited to 2 CPU cores and 2 GB RAM.` tabs={benchmark_tabs[0..]} run_url={bench_run.url} run_date={bench_run.date} />

Code Examples

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

)} /> )} /> )} /> )} /> )} /> )} /> )} /> )} />)} />
); } const Deployment = struct { icon_fn: *const fn (zx.Allocator) zx.Component, title: []const u8, description: []const u8 }; const Feature = struct { icon_fn: *const fn (zx.Allocator) zx.Component, title: []const u8, description: []const u8 }; fn FeatureCard(allocator: zx.Allocator, props: Feature) zx.Component { const IconComponent = props.icon_fn(allocator); return (
{IconComponent}

{props.title}

{props.description}

); } const TooltipMetric = struct { label: []const u8, value: []const u8, }; const BenchmarkRow = struct { label: []const u8, value: f64, display: []const u8, url: []const u8, tooltip_metrics: []const TooltipMetric = &[_]TooltipMetric{}, }; const BenchmarkRowViewProps = struct { row: BenchmarkRow, normalized_value: f64, }; const BenchmarkTab = struct { id: []const u8, label: []const u8, metric: []const u8, footnote: []const u8, rows: []const BenchmarkRow, checked: bool, lower_is_better: bool = false, }; const BenchmarksSectionProps = struct { eyebrow: []const u8, title: []const u8, subtitle: []const u8, tabs: []const BenchmarkTab, run_url: []const u8 = "", run_date: []const u8 = "", }; fn buildBenchTabStyles(allocator: zx.Allocator, container_id: []const u8, tabs: []const BenchmarkTab) []const u8 { var out = std.array_list.Managed(u8).init(allocator); defer out.deinit(); for (tabs) |tab| { out.appendSlice("#") catch unreachable; out.appendSlice(container_id) catch unreachable; out.appendSlice(":has(#") catch unreachable; out.appendSlice(tab.id) catch unreachable; out.appendSlice(":checked) .benchmarks-panel[data-tab=\"") catch unreachable; out.appendSlice(tab.id) catch unreachable; out.appendSlice("\"] { display: block; }\n") catch unreachable; out.appendSlice("#") catch unreachable; out.appendSlice(container_id) catch unreachable; out.appendSlice(":has(#") catch unreachable; out.appendSlice(tab.id) catch unreachable; out.appendSlice(":checked) label[for=\"") catch unreachable; out.appendSlice(tab.id) catch unreachable; out.appendSlice("\"] { color: #0c0f14; background: #4ade80; border-color: transparent; box-shadow: 0 8px 20px rgba(74, 222, 128, 0.25); }\n") catch unreachable; } return allocator.dupe(u8, out.items) catch unreachable; } fn BenchmarkRowView(allocator: zx.Allocator, props: BenchmarkRowViewProps) zx.Component { const style_value = std.fmt.allocPrint(allocator, "--value: {d:.3};", .{props.normalized_value}) catch unreachable; return (
{if (props.row.url.len > 0) ( {props.row.label} ) else ( {props.row.label} )}
{props.row.display}
{for (props.row.tooltip_metrics) |metric| (
{metric.label} {metric.value}
)}
); } fn normalizeValue(value: f64, rows: []const BenchmarkRow) f64 { if (rows.len == 0) return 0; var max_value = rows[0].value; for (rows[1..]) |row| { if (row.value > max_value) max_value = row.value; } if (max_value == 0) return 0; return value / max_value; } fn BenchmarksPanel(allocator: zx.Allocator, tab: BenchmarkTab) zx.Component { const panel_id = std.fmt.allocPrint(allocator, "panel-{s}", .{tab.id}) catch unreachable; const tab_id = std.fmt.allocPrint(allocator, "tab-{s}", .{tab.id}) catch unreachable; return (
//
{tab.metric}
{for (tab.rows) |row| ( )}
{tab.footnote}
); } fn BenchmarksSection(allocator: zx.Allocator, props: BenchmarksSectionProps) zx.Component { const tab_styles = buildBenchTabStyles(allocator, "benchmarks-tabs", props.tabs); return (
{props.eyebrow}

{props.title}

{props.subtitle}

{for (props.tabs) |tab| ( <> {if (tab.checked) ( ) else ( )} )}
{for (props.tabs) |tab| (BenchmarksPanel(allocator, tab))}
{if (props.run_url.len > 0) (
Last benchmarked on {props.run_date} View CI run →
)}
); } const DeploymentSectionProps = struct {}; fn DeploymentSection(allocator: zx.Allocator, _: DeploymentSectionProps) zx.Component { return (

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.

{for (deployments) |d| (
{d.icon_fn(allocator)}

{d.title}

{d.description}

)}
); } const FeatureExampleProps = struct { title: []const u8, child: zx.Component, wide: bool, }; fn FeatureExample(allocator: zx.Allocator, props: FeatureExampleProps) zx.Component { const class_name = if (props.wide) "feature-example feature-example--wide" else "feature-example"; return (
{props.title}
{props.child}
); } const CodeWindowProps = struct { title: []const u8, code: []const u8, section: []const u8, source: []const u8, }; const CodeTab = struct { id: []const u8, label: []const u8, section: []const u8, code: []const u8, checked: bool, }; fn resolveCode(allocator: zx.Allocator, source: []const u8, section: []const u8, fallback: []const u8) []const u8 { const raw = if (section.len > 0 and source.len > 0) util.extractSection(allocator, source, section) else fallback; return util.highlightZx(allocator, raw) catch raw; } fn CodeWindow(allocator: zx.Allocator, props: CodeWindowProps) zx.Component { const highlighted = resolveCode(allocator, props.source, props.section, props.code); return (
{props.title}
{highlighted}
); } const CodeWindowTabsProps = struct { id: []const u8, name: []const u8, title: []const u8, tabs: []const CodeTab, video_url: []const u8, source: []const u8, }; const CodePreviewExampleProps = struct { title: []const u8, section: []const u8, source: []const u8, code: []const u8, preview: zx.Component, }; fn CodePreviewExample(allocator: zx.Allocator, props: CodePreviewExampleProps) zx.Component { const highlighted = resolveCode(allocator, props.source, props.section, props.code); return (
{if (false) (
)}
{props.title}
{highlighted}
Preview
{props.preview}
); } fn buildTabStyles(allocator: zx.Allocator, container_id: []const u8, tabs: []const CodeTab) ![]const u8 { var out = std.array_list.Managed(u8).init(allocator); defer out.deinit(); for (tabs) |tab| { try out.appendSlice("#"); try out.appendSlice(container_id); try out.appendSlice(":has(#"); try out.appendSlice(tab.id); try out.appendSlice(":checked) .code-example-panel[data-tab=\""); try out.appendSlice(tab.id); try out.appendSlice("\"] { display: block; }\n"); } return try allocator.dupe(u8, out.items); } fn CodeWindowTabs(allocator: zx.Allocator, props: CodeWindowTabsProps) !zx.Component { const tab_styles = try buildTabStyles(allocator, props.id, props.tabs); return (
{for (props.tabs) |tab| ( <> {if (tab.checked) ( ) else ( )} )}
{if (props.video_url.len > 0) ( )}
{if (props.title.len > 0) (
{props.title}
)}
{for (props.tabs) |tab| (renderTabPanel(allocator, props.source, tab))}
); } fn renderTabPanel(allocator: zx.Allocator, source: []const u8, tab: CodeTab) zx.Component { const highlighted = resolveCode(allocator, source, tab.section, tab.code); return (
{highlighted}
); } const InstallCLI = @import("./components/install_guide.zx").InstallCLI; const VersionMeta = @import("./components/version.zx").VersionMeta; const Examples = @import("./examples/feature_examples.zx"); const icons = @import("./components/icons.zx"); const util = @import("./reference/util.zig"); const root = @import("root"); const std = @import("std"); const zx = @import("zx");