Idioms, Style and Best Practices
48.1 Idiomatic Zig
✅ Prefer const everywhere. Use var only when mutating.
✅ Pass allocators explicitly. The caller owns returned memory. Document ownership.
✅ Pair every acquisition with defer/errdefer immediately on the next line.
✅ Use []const u8 for string parameters. Use slices over many-item pointers.
✅ Make illegal states unrepresentable: tagged unions, enums, optionals, packed struct for flags.
✅ Use try liberally. Use specific error sets in public APIs. Use a diagnostics struct for detailed errors.
✅ Use the init/deinit naming convention. Use decl literals (.init, .empty) for default instances.
✅ Write tests next to the code and use std.testing.allocator to catch leaks.
✅ Use comptime for genuine needs (generics, tables, validation), not for cleverness.
✅ Run zig fmt (and zig build fmt --check in CI).
❌ Don't ignore errors with catch unreachable unless it's truly impossible.
❌ Don't store pointers into growable containers across appends.
❌ Don't return slices of stack buffers.
❌ Don't overuse anytype in public APIs: concrete types give better errors and docs.
❌ Don't fight the language with hidden-control-flow patterns from other languages.
48.2 API Design Conventions
Type.init(...) returns a value or an error union. deinit(self, allocator) releases. create/destroy are for heap objects.
Unmanaged containers (store no allocator) are the default trend. Accept allocator per call.
Options structs with defaults instead of many parameters.
Return ?T for "not found" and an error for "failed".
Accept *std.Io.Writer / *std.Io.Reader for streaming I/O (0.15+).
48.3 Upgrading Between Zig Versions
Read the release notes, compile, and fix errors. zig fmt auto-fixes some syntax changes.
Pin the Zig version in build.zig.zon (minimum_zig_version) and CI (e.g., mlugg/setup-zig GitHub Action).
Keep dependencies' versions compatible with your Zig version (many projects keep branches per Zig release).
48.4 CI Example (GitHub Actions)
jobs:
test:
strategy:
matrix: { os: [ubuntu-latest, macos-latest, windows-latest] }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with: { version: 0.15.1 }
- run: zig build fmt
- run: zig build test --summary all
- run: zig build -Doptimize=ReleaseSafe