# Release Modes

### Release Modes

Zig can build the same program in different optimization modes.

The optimization mode controls how the compiler balances debugging, safety checks, speed, and binary size.

In `build.zig`, release modes usually come from this line:

```zig
const optimize = b.standardOptimizeOption(.{});
```

Then the executable uses it:

```zig
const exe = b.addExecutable(.{
    .name = "hello",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    }),
});
```

The important field is:

```zig
.optimize = optimize
```

That connects the command-line option to the artifact.

#### The Four Main Modes

Zig has four common optimization modes:

```text
Debug
ReleaseSafe
ReleaseFast
ReleaseSmall
```

You select one with:

```bash
zig build -Doptimize=Debug
zig build -Doptimize=ReleaseSafe
zig build -Doptimize=ReleaseFast
zig build -Doptimize=ReleaseSmall
```

`Debug` is the default in many projects.

#### Debug

`Debug` mode is for development.

It keeps safety checks, keeps useful debug information, and avoids heavy optimization. The resulting program is usually slower and larger, but easier to inspect.

Use it when writing code:

```bash
zig build
```

or explicitly:

```bash
zig build -Doptimize=Debug
```

This is the best mode when you want readable stack traces, easier debugging, and stronger runtime checking.

#### ReleaseSafe

`ReleaseSafe` mode builds an optimized program while keeping many safety checks.

Use it when you want better performance than `Debug`, but still want runtime safety checks.

```bash
zig build -Doptimize=ReleaseSafe
```

This is a good mode for production software where correctness matters more than maximum speed.

#### ReleaseFast

`ReleaseFast` mode optimizes for speed.

```bash
zig build -Doptimize=ReleaseFast
```

This mode may remove safety checks that would slow the program down. The result can be faster, but bugs such as invalid memory access or integer overflow may become harder to detect.

Use this mode only after testing carefully.

#### ReleaseSmall

`ReleaseSmall` mode optimizes for binary size.

```bash
zig build -Doptimize=ReleaseSmall
```

This is useful for embedded systems, command-line tools, WebAssembly, containers, and distribution where small files matter.

The program may sacrifice some speed to become smaller.

#### Choosing a Mode

| Mode | Main goal | Best use |
|---|---|---|
| `Debug` | Easy debugging | Daily development |
| `ReleaseSafe` | Speed with safety checks | Conservative production builds |
| `ReleaseFast` | Maximum speed | Performance-critical builds |
| `ReleaseSmall` | Small binary size | Embedded, WASM, small tools |

A simple workflow is:

```bash
zig build test
zig build -Doptimize=ReleaseSafe
zig build -Doptimize=ReleaseFast
zig build -Doptimize=ReleaseSmall
```

First test the code. Then build the release form you need.

#### Optimization Mode Is Compile-Time Information

Your Zig code can inspect the selected mode:

```zig
const builtin = @import("builtin");

pub fn main() void {
    if (builtin.mode == .Debug) {
        // debug-only behavior
    }
}
```

This condition is known at compile time.

That means debug-only code can disappear from release builds.

For example:

```zig
const builtin = @import("builtin");
const std = @import("std");

pub fn logDebug(comptime fmt: []const u8, args: anytype) void {
    if (builtin.mode == .Debug) {
        std.debug.print(fmt, args);
    }
}
```

In `Debug`, this prints messages.

In release modes, the compiler can remove the branch.

#### Safety Checks

Safety checks help catch mistakes while the program runs.

Examples include:

```text
integer overflow checks
array bounds checks
some invalid pointer use checks
unreachable code checks
```

These checks are especially useful during development.

In faster release modes, some checks may be disabled for performance. That is why testing in `Debug` and `ReleaseSafe` is useful before shipping a `ReleaseFast` binary.

#### Debug Info

Debug information helps debuggers map machine code back to source code.

In `Debug`, this information is usually more useful.

In release modes, the compiler may optimize code so heavily that debugging becomes harder. Variables may disappear, functions may be inlined, and source lines may not map cleanly to instructions.

That is normal for optimized builds.

#### Binary Size

Release modes can change binary size significantly.

`Debug` builds are often larger because they contain debug information and less optimized code.

`ReleaseSmall` tells the compiler to prefer smaller output.

For command-line tools, small binaries can make distribution easier. For embedded systems, size can be a hard limit.

#### Performance

`ReleaseFast` usually gives the best runtime performance.

But performance should be measured, not guessed.

Use benchmarks and profilers. A `ReleaseFast` binary is usually the right candidate for performance testing:

```bash
zig build -Doptimize=ReleaseFast
```

Do not benchmark `Debug` builds unless you are measuring development-time behavior.

#### Release Mode and Target Are Separate

This chooses the optimization mode:

```bash
zig build -Doptimize=ReleaseFast
```

This chooses the target:

```bash
zig build -Dtarget=x86_64-linux
```

You can combine them:

```bash
zig build -Dtarget=x86_64-linux -Doptimize=ReleaseFast
```

That command builds a fast release binary for Linux x86_64.

#### Common Mistakes

A common mistake is benchmarking a debug build. Debug builds are not meant to represent final speed.

Another mistake is using `ReleaseFast` too early. It may hide bugs that would be caught by safety checks.

Another mistake is assuming release mode controls linking. It does not. Static and dynamic linking are separate build choices.

Another mistake is forgetting to pass `optimize` into the module:

```zig
.optimize = optimize
```

If you define the option but do not use it, the artifact will not follow the selected mode.

#### The Important Idea

Release modes tell Zig what kind of binary you want.

Use `Debug` while writing code.

Use `ReleaseSafe` when you want optimized code with safety checks.

Use `ReleaseFast` when speed matters most.

Use `ReleaseSmall` when binary size matters most.

The standard pattern is:

```zig
const optimize = b.standardOptimizeOption(.{});
```

and then:

```zig
.optimize = optimize
```

inside the module you are building.

