Skip to main content

Variables and Constants

Zig provides two ways to declare identifiers: var for variables and const for constants.

Constants

Constants are declared with const and cannot be changed after initialization:
const x = 1234;

fn foo() void {
    // It works at file scope as well as inside functions.
    const y = 5678;

    // Once assigned, an identifier cannot be changed.
    // This would be a compile error:
    // y += 1;
}

Variables

Variables are declared with var and can be modified:
const print = @import("std").debug.print;

pub fn main() void {
    var x: i32 = undefined;
    x = 1;
    print("{d}", .{x});
}
Variables declared with var must have their types explicitly specified or inferred from initialization.

Container-Level Variables

Variables and constants can be declared at the container level (file scope):
var y: i32 = add(10, x);
const x: i32 = add(12, 34);

test "container level variables" {
    try expect(x == 46);
    try expect(y == 56);
}

fn add(a: i32, b: i32) i32 {
    return a + b;
}
Container-level variables are evaluated in dependency order, not declaration order.

Assignment

Direct Assignment

Assignment in Zig is straightforward with the = operator:
var x: i32 = 10;
x = 20; // reassignment

Undefined Values

You can use undefined to leave a variable uninitialized:
var x: i32 = undefined;
x = 1; // must assign before use
Using undefined values before assignment leads to undefined behavior. Use it only when you’re certain you’ll assign a value before reading.

Comments

Zig supports two types of comments:

Line Comments

Line comments start with // and continue to the end of the line:
const print = @import("std").debug.print;

pub fn main() void {
    // Comments in Zig start with "//" and end at the next LF byte (end of line).
    // The line below is a comment and won't be executed.

    //print("Hello?", .{});

    print("Hello, world!\n", .{}); // another comment
}

Doc Comments

Doc comments are used for documentation generation and start with ///:
/// This is a doc comment for a function.
/// It can span multiple lines.
pub fn myFunction() void {
    // Regular comment
}
Use doc comments (///) for public APIs that need documentation, and regular comments (//) for implementation details.

Compile-Time vs Runtime

Zig distinguishes between compile-time and runtime values:
const builtin = @import("builtin");
const separator = if (builtin.os.tag == .windows) '\\' else '/';
This expression is evaluated at compile-time, allowing for platform-specific constants without runtime overhead.

Identifiers

Standard identifiers must start with a letter or underscore and contain only alphanumeric characters and underscores:
const my_variable = 10;
const _private = 20;
const value123 = 30;

Best Practices

  • Prefer const over var when the value doesn’t need to change
  • Use descriptive names for identifiers
  • Initialize variables at declaration when possible
  • Use undefined sparingly and only when necessary for performance

Build docs developers (and LLMs) love