Variables and Constants

for Zig 0.15.2 Buy

Variables and Constants

Create a file named hello_user.zig with the following content:

hello_user.zig

const std = @import("std");

pub fn main() void {

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

}

        Remember how, in the previous example, to write a line of text, we did this:

 @import("std").debug.print("Hello world!\n", .{});

The @import command imports Zig’s standard library into our program. In that first example, we imported and used the library all in the same line. In the second example, we imported the library at the top of the program, outside the main function.

 const std = @import("std");

And as you can see, when importing the library, now instead of immediately using debug.print, we assign the library to an identifier (a symbolic name), in this case: std.

The identifier could be different. We could write something like:

 const my_fav_lib = @import("std");

But that wouldn’t make much sense. The standard library is usually assigned to the identifier std. The identifiers we use to name things should be self-explanatory.

Using the reserved word const before an identifier means we’re declaring a constant.

Declaring a constant in Zig means assigning a value to an identifier (like std or my_fav_lib), and that value can’t be changed while the program runs.

For example, we can assign other kinds of values to constants:

  const n_a = 1;

In this case, we’re assigning the value 1 to the identifier n_a, and that value cannot be changed during the execution of the program.

Let’s try changing the constant n_a to the value 2.

const.zig

const std = @import("std");

pub fn main() void {

    const n_a = 1;

    n_a = 2;

}

If we try to run this program, we’ll see an error:

$ zig run constants.zig

constants.zig:6:5: error: cannot assign to constant

    n_a = 2;

    ^~~

The Zig compiler is telling us that we can’t (re)assign a value to a constant.

But what if we do want to change that value?

It’s very simple - we just need to use the keyword var instead of const in front of the identifier.

Putting the word var in front of the symbolic name means we’re declaring a variable. The value stored in a variable can be changed while the program is running.

vars.zig

const std = @import("std");

pub fn main() void {

    var n_a = 1;

    n_a = 2;

}

If we try to run vars.zig, we’ll see… Wait a second! The compiler has an objection:

$ zig run vars.zig

vars.zig:4:9: error: variable of type 'comptime_int' must be const or comptime

    var n_a = 1;

        ^~~

vars:5:7: note: to modify this variable at runtime, it must be given an explicit fixed-size number type

So what does this mean? The compiler needs to know what kind of data this variable will store. It’s not enough to just write var n_a = 1;, because Zig needs to know exactly what kind of number we will be using.

Right now, all this stuff about data types and number types might sound a bit confusing. It doesn’t matter. We’ll soon take a closer look at what data types mean in Zig - but for now, let’s just add an explicit type to the variable so we can run the program.

vars_2.zig

const std = @import("std");

pub fn main() void {

    var n_a: u8 = 1; // assign the type u8

    n_a = 2;

}

$ zig run vars_2.zig

We don’t get any output since we haven’t printed anything, but there’s no error either.

That means we successfully changed the value of the variable n_a.  Try playing around with what you’ve learned so far in the zenofzig.com playground to print this variable.

Here’s what we understand so far:

Declared using the keyword const before the identifier. Their value cannot change during program execution.

Declared using var. Their value can change while the program runs, but we need to specify the data type (u8, i32, etc.).

When to use variables and when to use constants

Imagine that in a game, you start with 3 lives. That’s a fixed rule, ideal for a constant. It doesn’t change while the program runs, and every time a new game starts, you get those same initial lives again. So we could write:

 const N_START_LIVES = 3;

However, the current number of lives we have during the game isn’t fixed: it can go from 0 (if we lose them all) to however many we manage to collect by finding extra lives.

This is clearly a variable, since it changes throughout each game.

 var n_lives = N_START_LIVES;

lives.zig

const std = @import("std");

// lives at the start of the game

const N_START_LIVES: u8 = 3;

pub fn main() void {

    // current lives at the start of the game

    var n_lives = N_START_LIVES;

    std.debug.print("You have {d} lives\n", .{n_lives});

    std.debug.print("Oh no! You just died.\n", .{});

    // the player lost one life

    n_lives -= 1;

    std.debug.print("Now you have {d} lives\n", .{n_lives});

    std.debug.print("You found an extra life.\n", .{});

    // the player picked up an extra life

    n_lives += 1;

    std.debug.print("Now you have {d} lives\n", .{n_lives});

}

$ zig run lives.zig

You have 3 lives

Oh no! You just died.

Now you have 2 lives

You found an extra life.

Now you have 3 lives

Following this example, we should aim to use:

Structure of a program
Comments
© 2025 - 2026 Zen of Zig