Deploying a Zig web server to Cloud Run in ten seconds

Jeff Huleatt

portrait of Jeff Huleatt

Zig can cross-compile to Linux from any platform, and Cloud Run can deploy from source without a build step using OS-only base images, which are minimal container images without any language runtime. After cross-compiling a Zig web server locally, the deploy to Cloud Run only takes about ten seconds thanks to the small image size and skipping the Cloud Build step.

The Zig web server

Here’s a basic Zig web server using httpz. The important part for Cloud Run is reading the PORT environment variable and binding to 0.0.0.0, per the Cloud Run container contract.

const std = @import("std");
const httpz = @import("httpz");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    var env = try std.process.getEnvMap(allocator);
    defer env.deinit();
    const port = std.fmt.parseInt(u16, env.get("PORT") orelse "8080", 10) catch 8080;

    var server = try httpz.Server(void).init(allocator, .{
        .port = port,
        .address = "0.0.0.0",
    }, {});
    defer {
        server.stop();
        server.deinit();
    }

    var router = try server.router(.{});
    router.get("/", greetUser, .{});

    std.debug.print("Zig web server listening on port {any}\n", .{port});
    try server.listen();
}

fn greetUser(req: *httpz.Request, res: *httpz.Response) !void {
    std.debug.print("Handling a {any} request to {s}\n", .{ req.method, req.url.path });
    res.status = 200;
    res.content_type = .TEXT;
    res.body = "Hello from Zig!";
}

Cross-compile and deploy

First, cross-compile for Cloud Run’s Linux environment:

zig build -Dtarget=x86_64-linux

This assumes your build.zig passes the target to b.standardTargetOptions(). If you started from zig init, it already does.

Then deploy to Cloud Run with --no-build, pointing --source at the compiled binary:

gcloud beta run deploy zig-web-server \
  --source zig-out/bin \
  --no-build \
  --base-image=osonly24 \
  --command=./web-server \
  --region=us-east1

When I tested this, the deploy completed in about 10 seconds.