Skip to content

`const` and `var`

Zig has two kinds of variable declarations:

const and var

Zig has two kinds of variable declarations:

const

and

var

A const declaration creates a name whose value cannot change.

const year = 2026;

A var declaration creates a mutable variable.

var count = 0;

The difference is important. Zig prefers immutability when possible.

Consider:

const std = @import("std");

pub fn main() void {
    const x = 10;
    std.debug.print("{d}\n", .{x});
}

This program is correct.

Now try to assign a new value:

const x = 10;
x = 20;

The compiler reports an error. A constant cannot be changed after initialization.

A mutable variable may be assigned another value:

const std = @import("std");

pub fn main() void {
    var n = 1;

    n = 2;
    n = 3;

    std.debug.print("{d}\n", .{n});
}

The output is:

3

A declaration must always be initialized.

This is valid:

const x = 5;
var y = 10;

This is not:

var n; // error

Zig does not allow uninitialized local variables unless the programmer explicitly asks for undefined memory.

var n: i32 = undefined;

undefined means the value is not initialized. Reading it before writing a value is an error.

Usually you should initialize variables normally.

var n: i32 = 0;

The compiler checks whether a mutable variable is actually mutated.

var x = 10;

If x is never changed, the compiler may suggest using const instead.

This helps keep programs simpler and safer.

A constant does not mean the data itself is always immutable. It means the binding cannot be changed.

Consider:

var data = [_]u8{ 1, 2, 3 };

const slice = data[0..];

slice always refers to the same slice, but the underlying array may still change.

data[0] = 9;

Now slice[0] is also 9.

The constant applies to the name, not necessarily to all reachable memory.

You may also create constant pointers and mutable pointers.

var x: i32 = 10;

const p = &x;

p always points to the same location.

But the value at that location may still change:

p.* = 20;

The expression:

p.*

means “the value pointed to by p”.

A mutable variable is useful when a value changes over time.

var sum: i32 = 0;

sum += 1;
sum += 2;
sum += 3;

A constant is useful when a value should stay fixed.

const max_users = 100;

Most declarations in Zig programs are constants.

This style has several advantages:

  • values cannot change accidentally
  • the compiler can reason more precisely
  • code is easier to read
  • fewer states exist in the program

A small example:

const std = @import("std");

pub fn main() void {
    const width = 80;
    const height = 25;

    const area = width * height;

    std.debug.print("{d}\n", .{area});
}

None of these values need mutation, so const is appropriate.

Now consider a loop:

const std = @import("std");

pub fn main() void {
    var i: usize = 0;

    while (i < 5) : (i += 1) {
        std.debug.print("{d}\n", .{i});
    }
}

Here i changes during execution, so it must be declared with var.

Use const by default. Use var only when mutation is necessary.

Exercises:

  1. Declare a constant named pi with value 3.14.

  2. Declare a variable named count, increment it three times, then print it.

  3. Write a program that swaps the values of two mutable variables.

  4. Create a mutable array and a constant slice that refers to it. Modify the array and print the slice contents.

  5. Declare a variable with undefined, assign a value later, then print it.