Zig good for webservers now?

context: we are building a CMS to compete with wordpress. This means we want to build a web server that can host many websites. As a matter of course, we will have a plugin system, this time using wasm so that plugins are properly sandboxed.

we have a basic prototype close to releasing, done in Rust with 700 LOC.

however, zig is looking very interesting – how is Zig’s story when it comes to web servers? Are there any big projects that are in networking? The biggest Zig projects are not web servers (Bun, Ghostty, tiger beetle).

last time was asked was here: https://www.reddit.com/r/Zig/comments/16umlvq/are_we_web_yet_for_zig/

and the answer was no

2 Likes

Hi, welcome!

AFAIK, jetzig is the most far-along among well-maintained, pure-Zig web frameworks:

Their README also has a good list of other Zig web projects.

3 Likes

this comment here said ZIg is too complicated for a web server: https://www.reddit.com/r/Zig/comments/1k82wg5/comment/mp3qu9r/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button

jetzig uses http.zig which operates in non-blocking mode on macOS/BSDs (kqueue) and Linux (epoll), but blocks with thread-per-connection on other platforms, notably Windows.

This makes jetzig a viable web framework.

Regarding the history of Zig subreddit, please read this blog post from the Zig creator himself:

1 Like

see this thread: Zig for web backend services

1 Like

The question is “Are low-level languages like Zig good for CMS?”

My bet - No

1 Like

Zig is really cool, but I don’t think it’s the kind of tool suited for the job here. I’m not expert in the web at all so I can’t really say, but Rust is much more mature, and seems to me like a better suit to get really good performance, safety and convenience for something in the web.

Of course Zig could do it, but I don’t think it would be the best tool for the job at hand.

2 Likes

I think where zig is going to shine is through the use of io_uring. Go will always struggle to use this API because of the C boundary. I don’t know Rust very well but I have read that integrating nicely with io_uring is not straight forward because of lifetime management.

Meanwhile, zig is in a perfect place to benefit from it. I’ve been working on an http server that tries to use all of the nice things from io_uring for a server. Specifically, you will see benefits over the threaded epoll model because you can get more done in kernel space and have fewer syscalls. You can get more done than the go model because you would limit your threads to one thread per CPU to reduce context switches.

The one caveat is that you want to put all IO back into the kernel to keep userspace doing as much work as it can. There aren’t enough libraries out there written this way to make it very viable off the shelf right now. But IMO this is where zig fits as a language for web development.

7 Likes

title of this post does not reflect the actual question

you are talknig about io within web server, but it’s small part of CMS

It’s the ‘small part of CMS’ which the question asked about. Plugins are going to be WASM, so those can be in any language which compiles to it, in principle.

As for the rest of it, who knows? Question doesn’t say, it asks about web servers.

Let me sharpen the question a bit: If you’re tasked with writing something like Apache or Nginx, would you use Zig or C?

1 Like

there is a tokio library for io_uring, is it good? GitHub - tokio-rs/io-uring: The `io_uring` library for Rust

I threw together a minimal prototype of an http server / router in Zig a while back, mainly as a way to see just how much I could abuse meta programming.

I ended up coming up with something that looked like this:

const Routes = struct {
    pub fn @"/hello/{}"(
        r: *http.Request,
        allocator: std.mem.Allocator, // optional: the router uses introspection on arg types to determine whether to pass this. It's a per thread arena allocator, that's reused
        name: []const u8,
        db: *Db, // also optional: this is injected based on the parameter type
    ) anyerror!void {
        // ...
    }
};

// ...

try http.serve(Routes, .{
    .threads = 16,
    .gpa = gpa,
    .inject = .{ db },
});

Overall, it was fun to write, and a horrible abuse of the type system. I might use it for a toy project at some point, but I wouldn’t use it in production. Performance was okay, even without using io-uring or epoll.

If you’re looking for something with bult-in DI, in the spirit of express + spring/guice then you might like what I’m working on:

It’s using http.zig as backend, and it’s not burried deep down so technically you can always switch to plain http.zig if you want to.

I’ve just merged a new version of the DI container, now with support for modules (including cross-module initialization). It’s not documented yet but I’ve also updated one OSS project which is using it so you can take that as reference:

2 Likes