Skip to main content

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;
Usage:
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;
HashMap Example:
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});
}
ArrayHashMap (preserves insertion order):
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");
Usage:
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,
};
Usage:
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.
Parsing 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});
}
Dynamic JSON with Value:
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 });
    }
}
Stringifying to JSON:
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,
};
Reading Files:
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});
}
Writing Files:
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);
}
Directory Operations:
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 });
    }
}
Path Constants:
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");
Usage:
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");
Thread Example:
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");
Hashing Example:
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");
Supports gzip, deflate, and other compression algorithms.

Time Operations

lib/std/std.zig:99-100
pub const time = @import("time.zig");
pub const tz = @import("tz.zig");
Usage:
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");
Making HTTP Requests:
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

Build docs developers (and LLMs) love