# Appendix F. Build Modes Reference

## Appendix F. Build Modes Reference

When Zig compiles a program, it can build the program in different modes.

A build mode changes things like:

- optimization level
- runtime safety checks
- debug information
- binary size
- execution speed

You choose the mode depending on what you are doing.

During development, you usually want safety and debugging support.

For production releases, you usually want speed or smaller binaries.

### F.1 The Four Main Build Modes

Zig has four standard optimization modes:

| Mode | Main Goal |
|---|---|
| `Debug` | Safety and debugging |
| `ReleaseSafe` | Optimized but still safety-checked |
| `ReleaseFast` | Maximum speed |
| `ReleaseSmall` | Small binary size |

These modes affect both performance and safety behavior.

### F.2 Debug Mode

Debug mode is the default during development.

Example:

```bash
zig build-exe main.zig
```

Or explicitly:

```bash
zig build-exe main.zig -ODebug
```

Characteristics:

| Property | Behavior |
|---|---|
| Optimization | Minimal |
| Runtime safety checks | Enabled |
| Debug symbols | Enabled |
| Execution speed | Slower |
| Binary size | Larger |

Debug mode catches many mistakes:

- integer overflow
- out-of-bounds indexing
- invalid unwraps
- some undefined behavior
- unreachable code reached

Example:

```zig
const x: u8 = 255;
const y = x + 1;
```

In Debug mode, this triggers overflow checking.

Debug mode is the best choice while learning Zig.

### F.3 ReleaseSafe Mode

ReleaseSafe keeps safety checks but adds optimization.

Example:

```bash
zig build-exe main.zig -OReleaseSafe
```

Characteristics:

| Property | Behavior |
|---|---|
| Optimization | High |
| Runtime safety checks | Enabled |
| Debug symbols | Reduced |
| Execution speed | Fast |
| Binary size | Medium |

This mode is useful when:

- correctness matters
- performance matters
- you still want runtime checks

ReleaseSafe is often a good production default for many applications.

### F.4 ReleaseFast Mode

ReleaseFast prioritizes speed.

Example:

```bash
zig build-exe main.zig -OReleaseFast
```

Characteristics:

| Property | Behavior |
|---|---|
| Optimization | Aggressive |
| Runtime safety checks | Mostly disabled |
| Debug symbols | Minimal |
| Execution speed | Very fast |
| Binary size | Medium |

This mode is dangerous if the program still contains bugs.

Example:

```zig
const x: u8 = 255;
const y = x + 1;
```

In ReleaseFast, overflow checking may be removed.

If the program has memory bugs or invalid assumptions, behavior may become unpredictable.

Use ReleaseFast only after testing carefully.

### F.5 ReleaseSmall Mode

ReleaseSmall optimizes for binary size.

Example:

```bash
zig build-exe main.zig -OReleaseSmall
```

Characteristics:

| Property | Behavior |
|---|---|
| Optimization | Size-focused |
| Runtime safety checks | Mostly disabled |
| Binary size | Small |
| Execution speed | Usually slower than ReleaseFast |

Useful for:

- embedded systems
- tiny utilities
- WebAssembly
- distribution-sensitive software

### F.6 Safety Checks

Different modes enable different runtime checks.

Common checks include:

| Check | Meaning |
|---|---|
| Integer overflow | Detect arithmetic overflow |
| Bounds checking | Detect invalid indexing |
| Null unwrap | Detect invalid optional access |
| Unreachable detection | Detect impossible code reached |
| Shift overflow | Detect invalid bit shifts |

Debug and ReleaseSafe keep most checks enabled.

ReleaseFast and ReleaseSmall disable many checks for performance.

### F.7 Example: Bounds Checking

Example:

```zig
const nums = [_]i32{ 1, 2, 3 };

pub fn main() void {
    const x = nums[10];
    _ = x;
}
```

In Debug mode:

- Zig detects invalid indexing
- program stops safely

In ReleaseFast:

- check may disappear
- behavior may become undefined

This is why development should happen in safe modes.

### F.8 Optimization Levels

Optimization changes generated machine code.

The compiler may:

- inline functions
- remove unused code
- reorder instructions
- eliminate allocations
- vectorize loops
- simplify calculations

Optimized code runs faster but becomes harder to debug.

Example problem:

```zig
var x = compute();
```

In optimized builds, `x` may disappear entirely if unused.

Debuggers may show confusing behavior because the optimizer changed the program layout.

### F.9 Debug Symbols

Debug symbols help debuggers understand the program.

They contain information about:

- variable names
- source locations
- stack traces
- function boundaries

Debug mode includes more symbol information.

Release builds usually reduce or strip it.

### F.10 Stack Traces

Safe modes produce better stack traces.

Example:

```zig
fn crash() void {
    unreachable;
}

pub fn main() void {
    crash();
}
```

Debug output may show:

- function names
- file names
- line numbers

This makes debugging much easier.

### F.11 Undefined Behavior

Undefined behavior means the language no longer guarantees correct behavior.

Examples:

| Bug | Example |
|---|---|
| Out-of-bounds access | Invalid indexing |
| Use-after-free | Reading freed memory |
| Invalid pointer | Dangling pointer |
| Overflow in unchecked mode | Arithmetic overflow |

In safe modes, Zig often detects these problems.

In fast modes, they may silently corrupt the program.

### F.12 Build Modes in `build.zig`

Most real Zig projects use `build.zig`.

Example:

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

Then:

```zig
.root_module.optimize = optimize;
```

Users choose the mode:

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

Common values:

| Value | Meaning |
|---|---|
| `Debug` | Safe development build |
| `ReleaseSafe` | Optimized safe build |
| `ReleaseFast` | Maximum performance |
| `ReleaseSmall` | Minimum size |

### F.13 Common Development Workflow

Typical workflow:

| Stage | Recommended Mode |
|---|---|
| Learning | `Debug` |
| Early development | `Debug` |
| Testing | `Debug` or `ReleaseSafe` |
| Benchmarking | `ReleaseFast` |
| Production server | `ReleaseSafe` or `ReleaseFast` |
| Embedded | `ReleaseSmall` |

### F.14 Debugging Optimized Code

Optimized code is harder to debug.

Problems include:

- variables disappear
- stack frames change
- functions inline automatically
- instruction order changes

If debugging becomes confusing:

1. switch back to Debug mode
2. reproduce the problem
3. fix the bug
4. return to optimized builds later

### F.15 Assertions and Build Modes

Assertions are checks inside your code.

Example:

```zig
std.debug.assert(x > 0);
```

In safe modes:

- failed assertion stops the program

In fast modes:

- some assertions may disappear

Do not rely on assertions for critical runtime validation in release builds unless you understand the mode behavior.

### F.16 Safety vs Performance

This is one of Zig’s core tradeoffs.

Debug mode favors correctness.

ReleaseFast favors performance.

Zig lets you choose explicitly.

The language does not assume:

- safety always matters more
- performance always matters more

Instead, you control the balance.

### F.17 Why ReleaseSafe Exists

Many languages force a difficult choice:

| Choice | Problem |
|---|---|
| Safe runtime | Slower |
| Fast runtime | Unsafe |

Zig’s ReleaseSafe mode is a middle ground.

You get:

- optimization
- many safety checks
- reasonable speed

This is valuable for servers, tooling, and infrastructure software where correctness matters.

### F.18 Measuring Performance Correctly

Never benchmark Debug builds.

Debug mode intentionally disables many optimizations.

Bad benchmark:

```bash
zig run benchmark.zig
```

Better:

```bash
zig build-exe benchmark.zig -OReleaseFast
./benchmark
```

Benchmark optimized builds only.

### F.19 Binary Size Differences

Different modes affect executable size.

Typical pattern:

| Mode | Size |
|---|---|
| Debug | Largest |
| ReleaseSafe | Smaller |
| ReleaseFast | Medium |
| ReleaseSmall | Smallest |

Exact results depend on:

- platform
- linker
- libraries
- debug info
- optimization opportunities

### F.20 Safety Checks Are Not Garbage Collection

A beginner confusion:

Runtime safety checks are not the same as garbage collection.

Zig safe modes detect invalid operations.

They do not automatically manage memory.

You still must:

- free memory
- manage ownership
- avoid dangling pointers

### F.21 Build Modes and Panics

When safety checks fail, Zig usually panics.

Examples:

- overflow
- invalid unwrap
- unreachable reached
- out-of-bounds access

Debug builds provide better panic diagnostics.

Release builds may produce less information.

### F.22 Cross Compilation and Modes

Build modes work with cross compilation too.

Example:

```bash
zig build-exe main.zig -target x86_64-windows -OReleaseSmall
```

This builds:

- Windows executable
- optimized for small size

Cross-compilation and optimization are independent settings.

### F.23 LTO and Advanced Optimization

Some advanced optimization features include:

| Feature | Meaning |
|---|---|
| Inlining | Replace function calls with function body |
| Vectorization | Use SIMD instructions |
| Dead code elimination | Remove unused code |
| Link-time optimization | Optimize across files |

Zig and LLVM perform many optimizations automatically in release modes.

### F.24 Which Mode Should Beginners Use?

Use Debug mode almost all the time at first.

```bash
zig run main.zig
```

Or:

```bash
zig build
```

Only switch to release modes when:

- benchmarking
- packaging
- testing production behavior
- reducing binary size

Correctness first. Optimization later.

### F.25 Quick Reference Table

| Mode | Speed | Safety | Debugging | Binary Size |
|---|---|---|---|---|
| Debug | Slow | High | Excellent | Large |
| ReleaseSafe | Fast | High | Good | Medium |
| ReleaseFast | Very fast | Lower | Harder | Medium |
| ReleaseSmall | Medium | Lower | Harder | Small |

### F.26 Practical Rule

A useful rule for Zig projects:

| Situation | Recommended Mode |
|---|---|
| Writing code | Debug |
| Fixing bugs | Debug |
| Running tests | Debug or ReleaseSafe |
| Profiling | ReleaseFast |
| Shipping software | ReleaseSafe or ReleaseFast |
| Embedded targets | ReleaseSmall |

Build modes are not just compiler switches. They are part of how Zig balances performance, safety, and control.

