⚡ Zig Guide LiveUnofficialbut fully verified
✓ Zig 0.18.0-dev.828+9da287565What's newOn an older Zig?Blograylib-zig

How this guide is verified

Every page here claims that its code works. This page gives the mechanism behind that claim, with enough detail that you can check it yourself. CI compiles and runs all 283 snippets against Zig 0.18.0-dev.828+9da287565. If one snippet fails, the site cannot be published.

What "verified" means

"Verified" means three separate things. Most documentation that claims to be tested does only the first.

  1. It compiles. The snippet compiles with the compiler that the footer names. That compiler is built from master, and does not come from a release.
  2. It runs. CI builds the binary and then runs it. If a snippet compiles and then panics on line one, that is a failure here.
  3. Its output is what the chapter says. Most snippets have a sibling file that records their exact expected stdout, byte for byte. A compiler change can make a program print a different result, while the program still compiles and runs. That is a failure too. A smoke test does not find this case.

One artifact, no second copy

The snippets are ordinary .zig files in the repository. This page does not contain a copy of the code that a person pasted in. When the site is built, the page reads the file from disk. Thus the listing in a chapter and the file that the compiler checked are the same bytes. The two cannot become different, because there is only one copy.

The Run button works in the same way. When CI compiles a snippet, the result is a .wasm file. The verification step runs that file, and your browser downloads the same file. There is no second build for the web, and no server compiles code on demand. When you press Run, your browser does the check again, on your machine.

What the build finds by itself

No list configures the snippets. The build scans the snippet directory and reads each file to classify it. Thus, when you add a snippet, you cannot forget to register it. When you delete a snippet, no stale entry stays behind.

  • If a file contains pub fn main, the build makes a program and captures its output. 208 of the 283 are programs.
  • The build makes each other file into a test binary, and runs it under the test runner. Thus its expect calls are real assertions. The other 75 are tests.
  • A sibling .expected file enables the comparison of the exact output. To enable it, add the file. You do not need to do more.
  • If the name of a file starts with an underscore, the file is a helper module that other snippets import. It is not a snippet.

The 32 that cannot run in a browser

A browser tab has no sockets, and no threads under the WebAssembly System Interface. It has no real filesystem, only an empty directory in memory, and no window to draw into. A snippet that needs one of these has a marker. The build compiles that snippet for the architecture of the build machine, not for wasm, and runs it there during verification. On the page, the snippet shows as ordinary highlighted code. A note tells you why there is no Run button. If one command can run the snippet, the note also gives you that command.

For a few snippets, the build compiles and links them, but never runs them. For example, the X11 chapter links against the real Xlib. A build that opened a window and waited for a keypress would stop the check forever. The compile and the link still find the problem that breaks these chapters: a change to the interface of the library.

The protocol chapters in the networking section still have Run buttons. The reason is that the codec, the command parser and the connection handler take bytes and return bytes. They do not read a socket directly, so CI can verify them, and they can run anywhere. Only the chapters that teach the socket itself need a real socket.

The 5 that are required to fail

Some chapters teach a runtime safety check, and the snippet makes the check fire. Examples are an out-of-bounds read and an integer overflow. For those snippets, the build turns safety checks on, and the verification is inverted. The build asserts that the program stops, with the exact message that a sibling file records. If the snippet exits successfully, or fails with different words, the build fails.

Thus CI checks a panic message in a chapter every night. Nobody must remember it from the day it was written. The guide uses this marker rarely, and only where the check itself is the lesson. The reason is that a safety build is about fourteen times larger to download than a normal build.

One rule tells what must never have this marker: a snippet whose important behaviour is undefined. Overflow is permitted, because a safety build promises a panic, and there is a correct message to pin. A read past the end of an array in a release build is not permitted. There is no correct answer, and a recorded expectation would assert undefined behaviour. Where this difference is important, the chapter states both halves, and shows only the defined half.

The 10 that are required not to compile

Some lessons are a compile error. Examples are a runtime value used as an array length, and a comptime loop that is longer than the branch quota. These snippets have a marker, and the build never makes a binary from them. The build compiles each one for wasm and asserts that the compiler stops. The compiler output must contain each line of a sibling file, in order.

The page shows the lines of that file under the code. Thus the error message that you read is the message that CI checks. If the snippet starts to compile, or the compiler changes its words, the build fails.

What happens every night

At 06:00 UTC, CI gets a new Zig built from master, and runs the full chain against it. CI verifies every snippet and builds the site. Then CI tests the built site in a real headless browser. The site publishes again only if all of these steps pass.

A check that runs when a person edits a page proves that the page was correct on the day of the edit. The nightly check proves that the page is correct today, on a compiler that did not exist when the chapter was written. When Zig changes something, the nightly check fails. The fix is to teach the new form, and to record what the old form was.

The browser check

The last gate loads the built site in headless Chromium, and acts like a reader. It presses Run on every playground and checks the output. It follows every internal link on every page, and fails on a link that does not resolve. It walks the full guide by its "next" arrows. Then it requires three things:

  • The walk reaches every chapter.
  • For every "next" arrow, the next page has the correct "previous" arrow.
  • Exactly two pages have one arrow missing: the pages at the two ends.

The gate also measures things that are not visible on the page. These things could break, and nobody would see it:

  • The contrast of the text against its real composited background, in each palette and in light and dark mode, against the WCAG AA thresholds.
  • On every page: a title, a description, one heading, one valid structured-data block, and a canonical URL that names the page itself.
  • Every page is in the sitemap, and every sitemap entry resolves.

What none of this checks

The prose. A chapter can compile, run and print exactly the correct output, and still have a bad explanation. A chapter can also be out of date about something that the compiler does not check. Corrections are welcome, and the fastest route is the issue tracker.

Two pages are outside the gate by design, and both pages tell you so. The chapter Migrate from an Older Zig shows "before" examples that do not compile, on purpose, to show what changed. The chapter on what changed in Zig 0.17shows 0.16.0 code and error messages. A person checked them by hand against both compilers, because CI has only the current compiler.

The build that does all of this is public, at github.com/rajeshpillai/zig-guide. See also about this guide.