# Installing Binaries

### Installing Binaries

A build does not only compile files. It can also install the results into a predictable output directory.

In Zig projects, the default install directory is usually:

```text
zig-out/
```

For an executable, the installed binary usually goes here:

```text
zig-out/bin/
```

So a project named `hello` may produce:

```text
zig-out/bin/hello
```

On Windows, the executable usually has `.exe`:

```text
zig-out/bin/hello.exe
```

#### Installing an Executable

A normal executable is created like this:

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

This defines the executable artifact, but by itself it does not necessarily install it.

To install it, call:

```zig
b.installArtifact(exe);
```

A complete minimal example:

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

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

    b.installArtifact(exe);
}
```

Now this command:

```bash
zig build
```

builds the executable and installs it under `zig-out/bin`.

#### Build Cache vs Install Directory

Zig uses build caches internally.

You may see directories such as:

```text
.zig-cache/
zig-cache/
```

These are not the main output you should give to users.

The installed output is the important one:

```text
zig-out/
```

A simple mental model:

```text
cache: files Zig uses while building
zig-out: files your project intentionally installs
```

When packaging or copying your program, usually look in `zig-out`, not the cache.

#### Changing the Install Prefix

You can change the install directory with `--prefix`.

```bash
zig build --prefix dist
```

Now the installed binary goes under:

```text
dist/bin/
```

For example:

```text
dist/bin/hello
```

This is useful when preparing a release folder.

You can also use an absolute path:

```bash
zig build --prefix /tmp/myapp
```

Then Zig installs into:

```text
/tmp/myapp/bin/
```

#### Installing Multiple Binaries

A project can install more than one executable.

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

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

b.installArtifact(server);
b.installArtifact(client);
```

After:

```bash
zig build
```

you may get:

```text
zig-out/bin/server
zig-out/bin/client
```

This is common for tools that ship several commands.

#### Installing Libraries

Libraries can be installed too.

A static library:

```zig
const lib = b.addStaticLibrary(.{
    .name = "mylib",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    }),
});

b.installArtifact(lib);
```

A shared library:

```zig
const lib = b.addSharedLibrary(.{
    .name = "mylib",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    }),
});

b.installArtifact(lib);
```

Libraries are normally installed under a library directory such as:

```text
zig-out/lib/
```

The exact file name depends on the platform and library type.

Examples:

```text
libmylib.a
libmylib.so
libmylib.dylib
mylib.dll
mylib.lib
```

#### Installing Header Files

If you build a library meant to be used from C, you may also want to install header files.

Suppose your project has:

```text
include/
  mylib.h
```

You can install that header with an install file step.

The exact APIs can vary by Zig version, but the idea is simple: copy a file from your source tree into the install prefix.

Conceptually:

```text
include/mylib.h -> zig-out/include/mylib.h
```

This gives C users both the library and the header they need.

A C-facing library usually installs at least:

```text
zig-out/lib/
zig-out/include/
```

#### Installing Data Files

Programs often need data files.

Examples:

```text
config templates
static assets
grammar files
runtime data
licenses
readme files
```

You can make the build install those files too.

The goal is to create an output tree like:

```text
zig-out/
  bin/
    app
  share/
    app/
      default.conf
      schema.json
```

This keeps runtime files next to the binary in a predictable structure.

For small beginner projects, you may not need this. For real applications, installing data files through the build system is better than asking users to copy files manually.

#### Install Steps Are Build Steps

Installing is also part of the build graph.

When you write:

```zig
b.installArtifact(exe);
```

you connect the executable to Zig’s default install step.

That means:

```bash
zig build
```

does not merely compile the executable. It also performs the install action.

If an artifact is not connected to an install step, it may still be built for another reason, but it will not appear in `zig-out`.

This distinction matters.

#### Build But Do Not Install

Sometimes you create an artifact only to run it or test it.

For example:

```zig
const run_cmd = b.addRunArtifact(exe);
const run_step = b.step("run", "Run the program");
run_step.dependOn(&run_cmd.step);
```

If you do not call:

```zig
b.installArtifact(exe);
```

then `zig build run` can still build and run the executable, but `zig build` may not install it into `zig-out/bin`.

Install only the outputs that should become part of the project’s public result.

#### Release Installation

Installation is especially useful for release builds.

For example:

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

This builds an optimized binary and installs it into:

```text
dist/
```

You can combine target, optimization, and prefix:

```bash
zig build -Dtarget=x86_64-linux -Doptimize=ReleaseFast --prefix dist/linux-x86_64
```

This creates a release output for one target.

Another target might use another prefix:

```bash
zig build -Dtarget=aarch64-linux -Doptimize=ReleaseFast --prefix dist/linux-aarch64
```

That gives a clean directory for each platform.

#### Common Mistakes

A common mistake is expecting an executable in `zig-out/bin` without calling:

```zig
b.installArtifact(exe);
```

Another mistake is copying files from the build cache instead of the install directory.

The cache is for Zig. The install directory is for you.

Another mistake is using one output directory for several targets and accidentally overwriting files with the same name.

For multi-target releases, use separate prefixes:

```text
dist/linux-x86_64
dist/linux-aarch64
dist/windows-x86_64
```

#### The Important Idea

Installing means copying build outputs into a stable output tree.

The common pattern is:

```zig
b.installArtifact(exe);
```

Then:

```bash
zig build
```

places the binary under:

```text
zig-out/bin/
```

Use `--prefix` when you want a different output directory:

```bash
zig build --prefix dist
```

For release builds, combine prefix, target, and optimization:

```bash
zig build -Dtarget=x86_64-linux -Doptimize=ReleaseFast --prefix dist/linux-x86_64
```

