Key Standard Library Modules
This guide covers the most important modules in Zig’s standard library, with practical examples extracted from the source code.Data Structures
ArrayList
Dynamic, growable array with automatic memory management:lib/std/std.zig:42-58
/// A contiguous, growable list of items in memory. This is a wrapper around a
/// slice of `T` values.
///
/// The same allocator must be used throughout its entire lifetime. Initialize
/// directly with `empty` or `initCapacity`, and deinitialize with `deinit` or
/// `toOwnedSlice`.
pub fn ArrayList(comptime T: type) type {
return array_list.Aligned(T, null);
}
pub const array_list = @import("array_list.zig");
/// Deprecated; use `array_list.Aligned`.
pub const ArrayListAligned = array_list.Aligned;
/// Deprecated; use `array_list.Aligned`.
pub const ArrayListAlignedUnmanaged = array_list.Aligned;
/// Deprecated; use `ArrayList`.
pub const ArrayListUnmanaged = ArrayList;
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var list = std.ArrayList(i32).init(allocator);
defer list.deinit();
try list.append(1);
try list.append(2);
try list.appendSlice(&[_]i32{ 3, 4, 5 });
std.debug.print("Length: {}\n", .{list.items.len});
std.debug.print("Items: {any}\n", .{list.items});
}
HashMap and ArrayHashMap
Hash-based key-value storage:lib/std/std.zig:1-6,21-22,32-35
pub const ArrayHashMap = array_hash_map.ArrayHashMap;
pub const ArrayHashMapUnmanaged = array_hash_map.ArrayHashMapUnmanaged;
pub const AutoArrayHashMap = array_hash_map.AutoArrayHashMap;
pub const HashMap = hash_map.HashMap;
pub const HashMapUnmanaged = hash_map.HashMapUnmanaged;
pub const AutoHashMap = hash_map.AutoHashMap;
pub const StringHashMap = hash_map.StringHashMap;
pub const StringArrayHashMap = array_hash_map.StringArrayHashMap;
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// AutoHashMap uses default hash function
var map = std.AutoHashMap([]const u8, i32).init(allocator);
defer map.deinit();
try map.put("one", 1);
try map.put("two", 2);
const value = map.get("one") orelse 0;
std.debug.print("Value: {}\n", .{value});
}
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var map = std.StringArrayHashMap(i32).init(allocator);
defer map.deinit();
try map.put("first", 100);
try map.put("second", 200);
try map.put("third", 300);
// Iteration preserves insertion order
var it = map.iterator();
while (it.next()) |entry| {
std.debug.print("{s}: {}\n", .{ entry.key_ptr.*, entry.value_ptr.* });
}
}
LinkedLists
lib/std/std.zig:14,30
pub const DoublyLinkedList = @import("DoublyLinkedList.zig");
pub const SinglyLinkedList = @import("SinglyLinkedList.zig");
const std = @import("std");
pub fn main() !void {
const Node = std.SinglyLinkedList(i32).Node;
var list = std.SinglyLinkedList(i32){};
var node1 = Node{ .data = 1 };
var node2 = Node{ .data = 2 };
var node3 = Node{ .data = 3 };
list.prepend(&node1);
list.prepend(&node2);
list.prepend(&node3);
var it = list.first;
while (it) |node| : (it = node.next) {
std.debug.print("{}\n", .{node.data});
}
}
BitSet
lib/std/std.zig:16-17,31
pub const DynamicBitSet = bit_set.DynamicBitSet;
pub const DynamicBitSetUnmanaged = bit_set.DynamicBitSetUnmanaged;
pub const StaticBitSet = bit_set.StaticBitSet;
const std = @import("std");
test "bitset operations" {
var set = std.StaticBitSet(128).initEmpty();
set.set(5);
set.set(42);
set.set(100);
try std.testing.expect(set.isSet(42));
try std.testing.expect(!set.isSet(43));
set.unset(42);
try std.testing.expect(!set.isSet(42));
}
String Formatting (fmt)
Powerful string formatting and parsing:lib/std/fmt.zig:1-24
//! String formatting and parsing.
pub const Alignment = enum {
left,
center,
right,
};
pub const Case = enum { lower, upper };
pub const Options = struct {
precision: ?usize = null,
width: ?usize = null,
alignment: Alignment = default_alignment,
fill: u8 = default_fill_char,
};
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Format to allocated string
const str = try std.fmt.allocPrint(allocator, "Value: {}, Hex: 0x{x}\n", .{ 42, 255 });
defer allocator.free(str);
// Format to buffer
var buf: [100]u8 = undefined;
const result = try std.fmt.bufPrint(&buf, "Pi: {d:.2}\n", .{3.14159});
// Format specifiers:
// {} - default formatting
// {d} - decimal
// {x} - lowercase hex
// {X} - uppercase hex
// {b} - binary
// {o} - octal
// {s} - string
// {c} - character
// {any} - debug print
}
JSON Parsing and Serialization
RFC 8259 compliant JSON support:lib/std/json.zig:1-10
//! JSON parsing and stringification conforming to RFC 8259.
//!
//! The low-level `Scanner` API produces `Token`s from an input slice or successive slices of inputs,
//! The `Reader` API connects a `std.Io.GenericReader` to a `Scanner`.
//!
//! The high-level `parseFromSlice` and `parseFromTokenSource` deserialize a JSON document into a Zig type.
//! Parse into a dynamically-typed `Value` to load any JSON value for runtime inspection.
//!
//! The low-level `writeStream` emits syntax-conformant JSON tokens to a `std.Io.Writer`.
//! The high-level `stringify` serializes a Zig or `Value` type into JSON.
const std = @import("std");
const Person = struct {
name: []const u8,
age: u32,
email: []const u8,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const json_string =
\\{"name": "Alice", "age": 30, "email": "[email protected]"}
;
var parsed = try std.json.parseFromSlice(Person, allocator, json_string, .{});
defer parsed.deinit();
std.debug.print("Name: {s}\n", .{parsed.value.name});
std.debug.print("Age: {}\n", .{parsed.value.age});
}
lib/std/json.zig:63-65
pub const ObjectMap = @import("json/dynamic.zig").ObjectMap;
pub const Array = @import("json/dynamic.zig").Array;
pub const Value = @import("json/dynamic.zig").Value;
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const json_string =
\\{"users": [{"id": 1, "active": true}, {"id": 2, "active": false}]}
;
var parsed = try std.json.parseFromSlice(std.json.Value, allocator, json_string, .{});
defer parsed.deinit();
const users = parsed.value.object.get("users").?.array.items;
for (users) |user| {
const id = user.object.get("id").?.integer;
const active = user.object.get("active").?.bool;
std.debug.print("User {}: {}\n", .{ id, active });
}
}
lib/std/json.zig:94
pub const Stringify = @import("json/Stringify.zig");
const std = @import("std");
const Config = struct {
port: u16,
host: []const u8,
debug: bool,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const config = Config{
.port = 8080,
.host = "localhost",
.debug = true,
};
var out = std.Io.Writer.Allocating.init(allocator);
defer out.deinit();
var stringify = std.json.Stringify{
.writer = &out.writer,
.options = .{ .whitespace = .indent_2 },
};
try stringify.write(config);
std.debug.print("{s}\n", .{out.written()});
}
File System (fs)
Comprehensive file system operations:lib/std/fs.zig:1-21
//! File System.
pub const AtomicFile = @import("fs/AtomicFile.zig");
pub const Dir = @import("fs/Dir.zig");
pub const File = @import("fs/File.zig");
pub const path = @import("fs/path.zig");
pub const has_executable_bit = switch (native_os) {
.windows, .wasi => false,
else => true,
};
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Read entire file
const file = try std.fs.cwd().openFile("config.txt", .{});
defer file.close();
const content = try file.readToEndAlloc(allocator, 1024 * 1024);
defer allocator.free(content);
std.debug.print("File content: {s}\n", .{content});
}
const std = @import("std");
pub fn main() !void {
const file = try std.fs.cwd().createFile("output.txt", .{});
defer file.close();
try file.writeAll("Hello, Zig!\n");
const data = [_]u8{ 1, 2, 3, 4, 5 };
try file.writeAll(&data);
}
const std = @import("std");
pub fn main() !void {
// Create directory
try std.fs.cwd().makeDir("new_folder");
// Open directory
var dir = try std.fs.cwd().openDir("new_folder", .{ .iterate = true });
defer dir.close();
// Iterate directory
var it = dir.iterate();
while (try it.next()) |entry| {
std.debug.print("{s} ({})\n", .{ entry.name, entry.kind });
}
}
lib/std/fs.zig:40-91
/// The maximum length of a file path that the operating system will accept.
pub const max_path_bytes = switch (native_os) {
.linux, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos,
.freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .illumos, .plan9,
.emscripten, .wasi, .serenity => posix.PATH_MAX,
.windows => windows.PATH_MAX_WIDE * 3 + 1,
else => if (@hasDecl(root, "os") and @hasDecl(root.os, "PATH_MAX"))
root.os.PATH_MAX
else
@compileError("PATH_MAX not implemented for " ++ @tagName(native_os)),
};
pub const max_name_bytes = switch (native_os) {
.linux, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos,
.freebsd, .openbsd, .netbsd, .dragonfly, .illumos, .serenity => posix.NAME_MAX,
.haiku => posix.NAME_MAX - 1,
.windows => windows.NAME_MAX * 3,
.wasi => windows.NAME_MAX * 3,
else => if (@hasDecl(root, "os") and @hasDecl(root.os, "NAME_MAX"))
root.os.NAME_MAX
else
@compileError("NAME_MAX not implemented for " ++ @tagName(native_os)),
};
Random Number Generation
lib/std/std.zig:28
pub const Random = @import("Random.zig");
const std = @import("std");
pub fn main() !void {
// Cryptographically secure random
var seed: u64 = undefined;
try std.posix.getrandom(std.mem.asBytes(&seed));
var prng = std.Random.DefaultPrng.init(seed);
const random = prng.random();
// Random integer
const rand_int = random.int(u32);
// Random in range
const dice_roll = random.intRangeAtMost(u8, 1, 6);
// Random float [0.0, 1.0)
const rand_float = random.float(f64);
// Shuffle slice
var items = [_]i32{ 1, 2, 3, 4, 5 };
random.shuffle(i32, &items);
std.debug.print("Random int: {}\n", .{rand_int});
std.debug.print("Dice roll: {}\n", .{dice_roll});
std.debug.print("Random float: {d}\n", .{rand_float});
}
Threads and Concurrency
lib/std/std.zig:37
pub const Thread = @import("Thread.zig");
const std = @import("std");
fn workerThread(id: usize) void {
std.debug.print("Thread {} running\n", .{id});
std.time.sleep(1 * std.time.ns_per_s);
std.debug.print("Thread {} done\n", .{id});
}
pub fn main() !void {
var threads: [4]std.Thread = undefined;
for (&threads, 0..) |*thread, i| {
thread.* = try std.Thread.spawn(.{}, workerThread, .{i});
}
for (threads) |thread| {
thread.join();
}
}
Cryptography and Hashing
lib/std/std.zig:69,77
pub const crypto = @import("crypto.zig");
pub const hash = @import("hash.zig");
const std = @import("std");
pub fn main() !void {
const data = "Hello, Zig!";
// SHA-256
var hash: [std.crypto.hash.sha2.Sha256.digest_length]u8 = undefined;
std.crypto.hash.sha2.Sha256.hash(data, &hash, .{});
std.debug.print("SHA-256: ", .{});
for (hash) |byte| {
std.debug.print("{x:0>2}", .{byte});
}
std.debug.print("\n", .{});
}
Compression
lib/std/std.zig:67
pub const compress = @import("compress.zig");
Time Operations
lib/std/std.zig:99-100
pub const time = @import("time.zig");
pub const tz = @import("tz.zig");
const std = @import("std");
pub fn main() void {
// Current timestamp
const timestamp = std.time.timestamp();
// Sleep
std.time.sleep(1 * std.time.ns_per_s); // 1 second
// Timing code
const start = std.time.nanoTimestamp();
// ... code to time ...
const end = std.time.nanoTimestamp();
const elapsed = end - start;
std.debug.print("Elapsed: {} ns\n", .{elapsed});
}
HTTP Client
lib/std/std.zig:80
pub const http = @import("http.zig");
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var client = std.http.Client{ .allocator = allocator };
defer client.deinit();
const uri = try std.Uri.parse("https://api.github.com/users/ziglang");
var header_buffer: [8192]u8 = undefined;
var request = try client.open(.GET, uri, .{
.server_header_buffer = &header_buffer,
});
defer request.deinit();
try request.send();
try request.wait();
var response_buffer: [4096]u8 = undefined;
const read = try request.readAll(&response_buffer);
std.debug.print("Response: {s}\n", .{response_buffer[0..read]});
}
Summary
Zig’s standard library provides:Rich Data Structures
ArrayList, HashMap, LinkedList, BitSet, and more
Text Processing
Formatting, JSON, Unicode, Base64
System APIs
File I/O, networking, processes, threads
Cryptography
Hashing, encryption, random generation
All standard library features are platform-agnostic where possible, with platform-specific implementations hidden behind consistent interfaces.
Next Steps
Overview
Standard library organization and structure
Allocators
Memory management patterns
Testing
Testing framework and best practices
Build System
Using std.Build for compilation