Skip to main content

Quick Start Guide

This guide will help you write, build, and run your first Zig program.

Hello, World!

Let’s start with the classic “Hello, World!” program.
1

Create a new file

Create a file named hello.zig:
touch hello.zig
2

Write the code

Add the following code from test/standalone/simple/hello_world/hello.zig:1-5:
hello.zig
const std = @import("std");

pub fn main() !void {
    try std.fs.File.stdout().writeAll("Hello, World!\n");
}
Let’s break down what this code does:
  • const std = @import("std"); - Import Zig’s standard library
  • pub fn main() !void - Define a public main function that may return an error
  • try - Unwrap the error union, returning early if an error occurs
  • std.fs.File.stdout().writeAll() - Write to standard output
3

Run the program

Use zig run to compile and execute in one step:
zig run hello.zig
Output:
Hello, World!
zig run is perfect for quick testing. It compiles and runs your program without creating a separate executable.

Building an Executable

To create a standalone executable, use zig build-exe:
1

Compile the program

zig build-exe hello.zig
This creates an executable named hello (or hello.exe on Windows).
2

Run the executable

./hello

Optimization Modes

Control the optimization level:
zig build-exe hello.zig
  • Debug: Full safety checks, no optimization (default)
  • ReleaseFast: Optimized for speed, safety checks disabled
  • ReleaseSmall: Optimized for binary size
  • ReleaseSafe: Optimized for speed, safety checks enabled

A More Interactive Example

Let’s create a simple number guessing game from test/standalone/simple/guess_number/main.zig:1-36:
guess_number.zig
const builtin = @import("builtin");
const std = @import("std");

pub fn main() !void {
    var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
    const out = &stdout_writer.interface;
    const stdin: std.fs.File = .stdin();

    try out.writeAll("Welcome to the Guess Number Game in Zig.\n");

    const answer = std.crypto.random.intRangeLessThan(u8, 0, 100) + 1;

    while (true) {
        try out.writeAll("\nGuess a number between 1 and 100: ");
        var line_buf: [20]u8 = undefined;
        const amt = try stdin.read(&line_buf);
        if (amt == line_buf.len) {
            try out.writeAll("Input too long.\n");
            continue;
        }
        const line = std.mem.trimEnd(u8, line_buf[0..amt], "\r\n");

        const guess = std.fmt.parseUnsigned(u8, line, 10) catch {
            try out.writeAll("Invalid number.\n");
            continue;
        };
        if (guess > answer) {
            try out.writeAll("Guess lower.\n");
        } else if (guess < answer) {
            try out.writeAll("Guess higher.\n");
        } else {
            try out.writeAll("You win!\n");
            return;
        }
    }
}
Run it:
zig run guess_number.zig
This example demonstrates:
  • Reading from standard input
  • Using the standard library’s random number generation
  • Error handling with catch
  • String parsing and manipulation
  • Control flow with while loops

Creating a Project with Build System

For larger projects, use Zig’s build system:
1

Initialize a new project

mkdir my-project
cd my-project
zig init
This creates:
  • build.zig - Build configuration
  • build.zig.zon - Package metadata
  • src/main.zig - Main source file
  • src/root.zig - Library root (optional)
2

Examine the build file

The build.zig file defines your build process. It’s written in Zig, similar to build.zig:1:
const std = @import("std");
const builtin = std.builtin;

pub fn build(b: *std.Build) !void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "my-project",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    b.installArtifact(exe);
}
3

Build the project

zig build
The executable is placed in zig-out/bin/.
4

Run with build system

zig build run
This builds and runs in one command.
5

Run tests

zig build test
Zig has built-in testing support. Tests are written using the test keyword.

Cross-Compilation

One of Zig’s superpowers is effortless cross-compilation:
# Compile for Windows from Linux
zig build-exe hello.zig -target x86_64-windows

# Compile for macOS ARM from Windows
zig build-exe hello.zig -target aarch64-macos

# Compile for Linux ARM from macOS
zig build-exe hello.zig -target aarch64-linux-musl
Use zig targets to see all available target triples.

Common Commands

Here are the most frequently used Zig commands:
CommandDescription
zig run <file>Compile and run a Zig file
zig build-exe <file>Compile to executable
zig build-lib <file>Compile to library
zig build-obj <file>Compile to object file
zig buildBuild using build.zig
zig test <file>Run tests in a file
zig fmt <file>Format Zig source code
zig initInitialize a new project
zig versionShow Zig version
zig zenDisplay the Zen of Zig
zig targetsList compilation targets

Error Handling Example

Zig’s error handling is explicit and compile-time verified:
const std = @import("std");

pub fn main() !void {
    const file = try std.fs.cwd().openFile("data.txt", .{});
    defer file.close();

    var buffer: [1024]u8 = undefined;
    const bytes_read = try file.read(&buffer);

    const stdout = std.fs.File.stdout();
    try stdout.writeAll(buffer[0..bytes_read]);
}
The ! in the return type indicates the function may return an error. Use try to propagate errors or catch to handle them.

Next Steps

Now that you’ve built your first Zig programs, continue learning:

Language Guide

Deep dive into Zig’s syntax and features

Standard Library

Explore Zig’s standard library

Build System

Master the Zig build system

Language Reference

Complete language reference

Getting Help

If you get stuck:

Build docs developers (and LLMs) love