I Tried to Write a HTTP Service in Zig and Failed

4 min read Original article ↗

Graham Jenson

I really like Zig. I have never wanted to write manually memory-managed code before. I don’t like C because it seems opaque and dangerous and I don’t like Rust for purely aesthetic reasons; but Zig is shiny and new and pretty and I can understand it intuitivly.

I wanted to write a small HTTP service in Zig (0.15.2) that used SQLite as a data store and could scale up. To do this I used the http.zig and zig.sqlite libraries which are pretty stable. I spent a couple weeks on this project, but kind of hit a few walls all at once which has lead me to the decision to abadon the spike.

Get Graham Jenson’s stories in your inbox

Join Medium for free to get updates from this writer.

Remember me for faster sign in

I am just going to record for my own sake the problems that I had, so when come back I can pick Zig up where I left off.

Things that are awesome

  1. It is so fast, soooo fast. In testing it is easily 2x faster than the exact same Go service deployed on fly.io.
  2. Allocators are very understandable. Also finding memory leaks is pretty easy since you can report unallocated memory at the end of a program. Using arena allocators during a HTTP call also removes a lot of stress.
  3. The concurrency with threads is not too complicated with mutexes, Signals and Events being pretty straight forward.
  4. comptime is super powerful because it is easy to use. Generating code that can pick up errors like std.debug.print("{s}", .{} ) removes runtime decisions and points of failure. I used comptime to generate an HTTP handler for static files, generate a struct that for DB migrations, and generate prepared SQL statements.
  5. Zig’s learning curve is not too steep, there were a few days I got stuck on a problem, but was usually able to get through it with a increased understanding (instead of increased dislike) of Zig.

Problems:

  1. Not having a string type was less of an issue but []const u8, []u8 , [_]u8, [:0]const u8 all being different really tripped me up a few times.
  2. Lack of packages was fine for most things. I needed a SQLite pool, so I build it; needed a .env parser, build it, needed a rate limiter, build it… A few things though were a bit more complicated, like an AWS S3 client. There are a few packages of unknown quality, and AWS does have a C S3 client. Finding something reliable without a giant amount of work might be impossible.
  3. When http.zig received a large volume of traffic calling server.stop causes a segfault. I think because it unallocates a requests currently being processed by a handler. This might be my fault, if I am holding it wrong but reliably shutting down was important for what I was building.
  4. zig build run swallows SIGTERMS so I have to use zig build && ./zig-out/bin/cmd. If you don’t the zig build process will keep running when the application closes and you have to manually kill.
  5. With the current 0.16.0 rewrite in IO layer, I think they removed some functionality like gzip. This made it difficult to implement compression for static HTTP handlers to save on bandwidth costs.
  6. Simple mistakes caused a lot of slowness, especially in the DB pool layer. Some thread mutex was too broad so one endpoint because very slow. Zig without my code is fast, but I can lose all benefit with small mistakes.
  7. Finding where memory is used is difficult. The process uses about 2x the amount of memory I think it should, it is not a memory leak but maybe I am allocating too many things just to be safe. Its not that bad, but I would like to be able to inspect the allocator during runtime and find where my memory is actually being used.
  8. AI/LLM/ Smart Autocomplete is a great tool to learn a programming language. This is limited with Zig and its fast moving standard library and API.
  9. docker build breaks for zig on my mac and I can’t fix it. When finding the problem a common response is “you don’t need docker with zig”, but if you are deploying to fly.io (or a lot of other places) you do need docker. BTW it deploys fine, so I know the docker file is good.

A lot of these problems may be my lack of understanding, or doing something wrong. I am sure a better programmer or someone who is more familiar with Zig could solve some of these issues. But I am just going to wait a bit before writing an HTTP service in Zig.

That being said, I still love Zig and want to use it for a project, I just don’t know what yet.