As of the current public Zig release line, the version is Zig 0.16, not Zig 1.16. Zig has not reached 1.0 yet. In this appendix, read “Zig 1.16” as “Zig 0.16” unless...
As of the current public Zig release line, the version is Zig 0.16, not Zig 1.16. Zig has not reached 1.0 yet. In this appendix, read “Zig 1.16” as “Zig 0.16” unless you are using a future release.
This appendix is a migration and review chapter. It is not meant to teach every feature from scratch. It collects the areas you should check when moving code to Zig 0.16.
A.1 What to Check First
When upgrading a Zig project, check these areas first:
build.zig
standard library imports
I/O APIs
allocator usage
container APIs
builtin functions
test commands
dependency declarationsMost Zig version upgrades affect code in these places before they affect ordinary arithmetic, structs, enums, or control flow.
A.2 Build System Changes
Zig projects usually depend on build.zig.
A simple executable project has this shape:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "app",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
b.installArtifact(exe);
}When a release changes the build system, old projects usually fail at compile time with clear errors. Fix build.zig first. After the build file works, move on to application code.
A.3 Standard Library API Movement
Zig’s standard library is still evolving.
That means names may move, signatures may change, and some helper functions may be replaced by clearer versions.
When this happens, do not guess. Use the compiler error as the guide.
For example, if old code says:
var list = std.ArrayList(u8).init(allocator);and the compiler rejects it, inspect the new std.ArrayList API for the exact constructor and ownership rules.
The important habit is this: treat the standard library as source code you can read. Zig makes that practical.
A.4 I/O API Review
Many beginner programs use stdout, stderr, and file readers.
A modern Zig style often creates a buffered writer, writes through its interface, then flushes:
var buffer: [1024]u8 = undefined;
var writer = std.fs.File.stdout().writer(&buffer);
const stdout = &writer.interface;
try stdout.print("hello\n", .{});
try stdout.flush();The key rule is simple: writing into a buffer is not enough. Flush when you need the output to appear.
A.5 Allocator Review
Allocator-heavy code should be checked carefully during upgrades.
Look for:
ArrayList creation
HashMap creation
arena usage
owned slice conversion
manual frees
errdefer cleanupThe pattern remains the same:
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();Use arenas when many allocations share one lifetime. Use a general-purpose allocator when objects have mixed lifetimes.
A.6 Builtins
Builtins begin with @.
Examples:
@import
@sizeOf
@alignOf
@intCast
@ptrCast
@bitCast
@memcpy
@memset
@compileErrorUpgrades often make builtin usage stricter. That is usually good. It means the compiler needs less guessing from context.
When a builtin call breaks, check:
number of arguments
result type
whether the destination type is inferred
whether the cast is still allowedA.7 Error Handling Still Looks the Same
The core error model remains stable:
fn readConfig() !Config {
return error.MissingConfig;
}Calling code handles errors with:
const config = try readConfig();or:
const config = readConfig() catch |err| {
std.debug.print("error: {s}\n", .{@errorName(err)});
return err;
};This is one of Zig’s central design points: failure stays visible in the type.
A.8 Comptime Still Matters
Generic code still often uses comptime:
fn add(comptime T: type, a: T, b: T) T {
return a + b;
}The compiler evaluates T at compile time, then creates code for the concrete type.
This remains one of the main differences between Zig and C.
A.9 Migration Strategy
Do not upgrade a large Zig project randomly.
Use this order:
1. upgrade Zig
2. run zig build
3. fix build.zig
4. fix imports and standard library API errors
5. fix builtin/cast errors
6. run tests
7. inspect warnings or behavior changes
8. update docs and examplesKeep each fix small. Build often.
A.10 What This Appendix Is For
This appendix gives you a checklist, not a complete changelog.
For exact release details, always read the official Zig release notes and the source code for the standard library version you are using.
The practical rule is simple: Zig upgrades are compiler-guided. Build the project, read the first error, fix it, then repeat.