Always use zigdoc to discover APIs for the Zig standard library and any
third-party dependencies.
Examples:
zigdoc std.fs
zigdoc std.posix.getuid
zigdoc ghostty-vt.Terminal
zigdoc vaxis.WindowRun task lint before merging. This includes zig fmt --check and ziglint on
all handwritten Zig files configured in .ziglint.zon; generated protobuf files
under src/proto are excluded. ziglint is required for code quality but
should stay out of the default zig build path.
Run the ziglint-only check with:
task lint:zigThese patterns reflect current Zig APIs and may differ from older documentation.
ArrayList:
var list: std.ArrayList(u32) = .empty;
defer list.deinit(allocator);
try list.append(allocator, 42);HashMap/StringHashMap (unmanaged):
var map: std.StringHashMapUnmanaged(u32) = .empty;
defer map.deinit(allocator);
try map.put(allocator, "key", 42);HashMap/StringHashMap (managed):
var map: std.StringHashMap(u32) = std.StringHashMap(u32).init(allocator);
defer map.deinit();
try map.put("key", 42);stdout/stderr Writer:
var buf: [4096]u8 = undefined;
const writer = std.fs.File.stdout().writer(&buf);
defer writer.flush() catch {};
try writer.print("hello {s}\n", .{"world"});build.zig executable/test:
b.addExecutable(.{
.name = "foo",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});Naming:
camelCasefor functions and methodssnake_casefor variables and parametersPascalCasefor types, structs, and enumsSCREAMING_SNAKE_CASEfor constants
Struct initialization: Prefer explicit type annotation with anonymous literals:
const foo: Type = .{ .field = value }; // Good
const foo = Type{ .field = value }; // AvoidFile structure:
//!doc comment describing the moduleconst Self = @This();(for self-referential types)- Imports:
std→builtin→ project modules const log = std.log.scoped(.module_name);
Functions: Order methods as init → deinit → public API → private helpers
Memory: Pass allocators explicitly, use errdefer for cleanup on error
Documentation: Use /// for public API, // for implementation notes.
Always explain why, not just what.
Tests: Inline in the same file, register in src/main.zig test block
Inspired by TigerStyle.
Assertions:
- Add assertions that catch real bugs, not trivially true statements
- Focus on API boundaries and state transitions where invariants matter
- Good: bounds checks, null checks before dereference, state machine transitions
- Avoid: asserting something immediately after setting it, checking internal function arguments
Function size:
- Soft limit of 70 lines per function
- Centralize control flow (switch/if) in parent functions
- Push pure computation to helper functions
Comments:
- Explain why the code exists, not what it does
- Document non-obvious thresholds, timing values, protocol details
When syntax-highlighting code in diagnostic messages:
- Blue: functions (
assert,init) - Purple: keywords (
and,or,const) - Yellow: identifiers, variables
- Magenta: types
- Dim: punctuation, backticks