Understanding zig build-exe
In the previous section, we used this command:
zig run hello.zigThat command compiles your Zig file and runs it immediately.
Now we will look at a different command:
zig build-exe hello.zigThis command compiles your Zig file and creates an executable file.
An executable file is a program you can run directly from your operating system.
Source File and Executable File
Start with this file:
hello.zigInside it, write:
const std = @import("std");
pub fn main() void {
std.debug.print("Hello, executable!\n", .{});
}Now run:
zig build-exe hello.zigZig reads hello.zig, checks the code, compiles it, links it, and creates an executable.
On Linux and macOS, the result is usually:
helloYou run it with:
./helloOn Windows, the result is usually:
hello.exeYou run it with:
.\hello.exeThe source file is the text you write.
The executable file is the program Zig creates.
What build-exe Means
The command has two parts:
zig build-exe hello.zigThe first part is:
zigThis runs the Zig tool.
The second part is:
build-exeThis tells Zig what kind of output you want.
The third part is:
hello.zigThis is the input file.
So the command means:
Use Zig to build an executable from hello.zig.Compile and Link
When you run zig build-exe, Zig does more than one thing.
First, it compiles your Zig code. Compilation checks the source code and turns it into lower-level machine instructions.
Second, it links the program. Linking connects your code with the pieces it needs from libraries and the operating system.
For a small program, this feels like one step. Internally, it has several stages.
You do not need to understand every stage yet. For now, remember this:
Source code goes in.
Executable program comes out.zig run vs zig build-exe
Both commands compile code, but they are used for different situations.
| Command | What it does | When to use it |
|---|---|---|
zig run hello.zig | Compile and run immediately | Quick experiments |
zig build-exe hello.zig | Compile and save executable | Creating a program file |
When learning, zig run is convenient.
When you want a real output file, use zig build-exe.
Running the Executable
After building, you run the executable directly.
On Linux and macOS:
./helloThe ./ means “run the file named hello in the current directory.”
This is needed because most Unix-like shells do not automatically search the current directory for programs.
On Windows PowerShell:
.\hello.exeThe .\ means the same idea: run the file in the current directory.
Choosing an Output Name
By default, Zig uses the source file name.
If the input is:
hello.zigthe output is usually:
helloor:
hello.exeYou can choose a different output name with -femit-bin.
zig build-exe hello.zig -femit-bin=myprogramNow the output is named:
myprogramOn Windows, you may choose:
zig build-exe hello.zig -femit-bin=myprogram.exeThis is useful when the file name and program name should be different.
Build Modes
Zig can build the same program in different modes.
A build mode controls safety checks, optimization, and debugging information.
The most common modes are:
| Mode | Purpose |
|---|---|
Debug | Best for development and learning |
ReleaseSafe | Optimized, but keeps many safety checks |
ReleaseFast | Optimized for speed |
ReleaseSmall | Optimized for small binary size |
By default, Zig builds in debug mode.
Debug mode is best while learning because it keeps helpful checks and better debugging information.
To build in release-fast mode:
zig build-exe hello.zig -O ReleaseFastTo build in release-safe mode:
zig build-exe hello.zig -O ReleaseSafeTo build in release-small mode:
zig build-exe hello.zig -O ReleaseSmallFor now, use the default mode unless you have a reason to change it.
What Debug Mode Gives You
Debug mode is slower than release mode, but it is better for learning.
It helps catch mistakes such as:
| Mistake | Example |
|---|---|
| Integer overflow | A number becomes too large for its type |
| Invalid array access | Code reads outside an array |
| Reaching impossible code | Code reaches unreachable |
| Better stack traces | Error messages are easier to inspect |
Speed matters later. Correctness matters first.
Use debug builds while writing and testing code.
A Simple Error Example
Try this program:
const std = @import("std");
pub fn main() void {
const items = [_]u8{ 1, 2, 3 };
std.debug.print("{}\n", .{items[10]});
}Build and run it:
zig build-exe hello.zig
./helloThe array has only three elements, but the program tries to access index 10.
In debug mode, Zig can catch this kind of error instead of silently continuing with invalid memory.
This is one reason debug builds are useful.
Cross Compilation Preview
One powerful feature of zig build-exe is cross compilation.
Cross compilation means building a program for a different platform.
For example, on one machine you can ask Zig to build for Linux:
zig build-exe hello.zig -target x86_64-linuxOr for Windows:
zig build-exe hello.zig -target x86_64-windowsOr for macOS on Apple Silicon:
zig build-exe hello.zig -target aarch64-macosYou do not need to master this now. The important idea is that Zig treats cross compilation as a normal compiler feature, not an advanced trick.
Common Beginner Problems
If you run:
zig build-exe hello.zigand see an error like:
error: file not foundmake sure your terminal is in the same directory as hello.zig.
You can list files in the current directory.
On macOS and Linux:
lsOn Windows PowerShell:
dirIf you build successfully but cannot run the program, check the file name.
On Linux and macOS, use:
./helloOn Windows, use:
.\hello.exeIf you type only:
helloon Linux or macOS, the shell may not find it. Use ./hello.
Mental Model
zig build-exe is the direct way to turn one Zig source file into one executable program.
You give Zig a .zig file.
Zig gives you a program file.
That is the basic build path:
hello.zig -> compiler -> helloLater, when projects become larger, we will use zig build and a build.zig file. But zig build-exe is the simplest place to start because it shows the core idea without extra project structure.