# Adding Dependencies

### Adding Dependencies

A Zig project can depend on other Zig packages.

A dependency is code that lives outside your project but is used by your project. It might be a library for parsing JSON, handling command-line flags, working with databases, building web servers, writing tests, or sharing common code between several projects.

In Zig, dependencies are described in two main places:

```text
build.zig.zon
build.zig
```

The `build.zig.zon` file lists the package dependencies.

The `build.zig` file tells the build system how to use them.

#### What Is `build.zig.zon`

A Zig package usually has a file named:

```text
build.zig.zon
```

The `.zon` part stands for Zig Object Notation. It is a small data format based on Zig syntax.

A simple `build.zig.zon` might look like this:

```zig
.{
    .name = .hello,
    .version = "0.1.0",
    .fingerprint = 0x123456789abcdef0,
    .minimum_zig_version = "0.16.0",
    .dependencies = .{},
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
    },
}
```

For a beginner, focus on these fields first:

```zig
.name = .hello,
.version = "0.1.0",
.dependencies = .{},
.paths = .{
    "build.zig",
    "build.zig.zon",
    "src",
},
```

The name identifies your package.

The version describes your package version.

The dependencies section lists external packages.

The paths section tells Zig which files belong to your package.

#### A Project Before Dependencies

Suppose we have this project:

```text
hello/
  build.zig
  build.zig.zon
  src/
    main.zig
```

The program is simple:

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

pub fn main() void {
    std.debug.print("Hello\n", .{});
}
```

It uses only the standard library. So the dependency list is empty:

```zig
.dependencies = .{},
```

That means the package does not need any external Zig packages.

#### Adding a Dependency to `build.zig.zon`

A dependency entry usually has a name, a URL, and a hash.

The shape looks like this:

```zig
.dependencies = .{
    .some_library = .{
        .url = "https://example.com/some_library.tar.gz",
        .hash = "1220...",
    },
},
```

The name is the local name your build file will use:

```zig
.some_library
```

The URL tells Zig where to download the package.

The hash tells Zig which exact package content is expected.

This is important. The hash protects the build from silently changing if the URL later points to different content.

#### Why the Hash Matters

A dependency should be repeatable.

If you build the same project next week, next month, or on another machine, you want the same dependency content.

The hash helps Zig verify that.

If the downloaded package does not match the hash, Zig stops. That is safer than building with unknown code.

This is one of the most important ideas in package management: dependency identity should be based on content, not only on a name or URL.

#### Getting the Correct Hash

When adding a dependency, you may not know the hash yet.

A common workflow is:

```text
add the dependency URL
run zig build
let Zig report the expected hash
copy the hash into build.zig.zon
run zig build again
```

So you might first write:

```zig
.dependencies = .{
    .some_library = .{
        .url = "https://example.com/some_library.tar.gz",
    },
},
```

Then run:

```bash
zig build
```

Zig can report that the dependency needs a hash. You copy the hash it gives you and place it into `build.zig.zon`.

After that, the dependency entry becomes complete:

```zig
.dependencies = .{
    .some_library = .{
        .url = "https://example.com/some_library.tar.gz",
        .hash = "1220abcd...",
    },
},
```

The exact hash string will depend on the package content.

#### Using a Dependency in `build.zig`

Listing a dependency in `build.zig.zon` only makes it available to the build system.

You still need to attach it to your executable, library, or tests.

Start with a normal executable:

```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 get the dependency:

```zig
const dep = b.dependency("some_library", .{
    .target = target,
    .optimize = optimize,
});
```

The string must match the dependency name from `build.zig.zon`, without the leading dot:

```zig
"some_library"
```

Then import one of its modules into your executable:

```zig
exe.root_module.addImport("some_library", dep.module("some_library"));
```

This says: inside the executable, allow source files to write:

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

The first `"some_library"` is the import name your code will use.

The second `dep.module("some_library")` asks the dependency package for a module with that name.

#### Full Example

Here is the general pattern:

```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,
        }),
    });

    const some_library = b.dependency("some_library", .{
        .target = target,
        .optimize = optimize,
    });

    exe.root_module.addImport(
        "some_library",
        some_library.module("some_library"),
    );

    b.installArtifact(exe);
}
```

Then `src/main.zig` can import it:

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

pub fn main() void {
    _ = some_library;
    std.debug.print("Program started\n", .{});
}
```

The dependency becomes part of the module graph for this executable.

#### Package Name vs Import Name

There are two names to understand.

The dependency name is used by the build system:

```zig
const dep = b.dependency("some_library", .{});
```

The import name is used by your source code:

```zig
const lib = @import("some_library");
```

They are often the same, but they do not have to be.

For example:

```zig
exe.root_module.addImport("lib", dep.module("some_library"));
```

Then your Zig code would write:

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

This can be useful if the package name is long, unstable, or not the name you want in your source code.

For beginners, keep them the same unless you have a reason to rename.

#### Dependencies Can Have Options

Some dependencies accept build options.

For example:

```zig
const dep = b.dependency("some_library", .{
    .target = target,
    .optimize = optimize,
    .enable_feature_x = true,
});
```

The exact options depend on the dependency.

The common options are:

```zig
.target = target
.optimize = optimize
```

These make the dependency build for the same target and optimization mode as your project.

That matters for cross-compilation. If your executable is being built for Linux ARM, its dependencies should usually be built for Linux ARM too.

#### Adding a Dependency to Tests

If your tests need the same dependency, add the import to the test artifact too.

```zig
const unit_tests = b.addTest(.{
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    }),
});

unit_tests.root_module.addImport(
    "some_library",
    some_library.module("some_library"),
);
```

Then your test code can also use:

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

A common beginner mistake is adding the dependency to the executable but forgetting to add it to tests. Each root module needs its own imports.

#### Local Dependencies

A dependency does not always need to come from the internet.

You can also depend on local code.

For example:

```text
my_app/
  build.zig
  build.zig.zon
  src/
    main.zig
  libs/
    parser/
      build.zig
      build.zig.zon
      src/
        parser.zig
```

In `build.zig.zon`, a local dependency can use a path:

```zig
.dependencies = .{
    .parser = .{
        .path = "libs/parser",
    },
},
```

Then in `build.zig`:

```zig
const parser = b.dependency("parser", .{
    .target = target,
    .optimize = optimize,
});

exe.root_module.addImport("parser", parser.module("parser"));
```

Local dependencies are useful for monorepos or for splitting a large project into smaller packages.

#### Project Modules vs External Dependencies

Not every shared file needs to be an external dependency.

Sometimes you only need another module inside the same project.

For example:

```text
src/
  main.zig
  math.zig
```

In `main.zig`, you can write:

```zig
const math = @import("math.zig");
```

That is a file import inside the same package.

Use a dependency when the code is a separate package with its own build file, version, and reuse boundary.

Use a local file import when the code is simply part of the same program.

#### Where Dependencies Are Stored

Zig downloads and caches dependencies outside your source tree.

This keeps your project directory clean. Your repository usually stores:

```text
build.zig
build.zig.zon
src/
```

It does not need to store downloaded dependency contents.

The build cache can be recreated by running:

```bash
zig build
```

This is why the URL and hash are important. They let Zig fetch the same dependency again.

#### Updating a Dependency

To update a dependency, you change its URL or hash in `build.zig.zon`.

For example, you might move from one tagged archive to another:

```zig
.url = "https://example.com/some_library/archive/v0.2.0.tar.gz",
```

to:

```zig
.url = "https://example.com/some_library/archive/v0.3.0.tar.gz",
```

Then update the hash.

Dependency updates should be deliberate. Build the project, run tests, and check whether the dependency changed its public API.

#### Common Mistakes

The first common mistake is putting the dependency in `build.zig.zon` but never adding it to the executable module.

The second common mistake is using the wrong module name:

```zig
dep.module("wrong_name")
```

A dependency package decides which modules it exposes. You must use one of those module names.

The third common mistake is forgetting tests:

```zig
exe.root_module.addImport(...)
```

does not automatically add the import to:

```zig
unit_tests.root_module
```

The fourth common mistake is assuming the import name must match the package name. It does not. The import name is chosen by your build file.

#### The Important Idea

Adding a dependency has two parts.

First, declare where the dependency comes from in `build.zig.zon`.

Second, attach the dependency’s module to the build target that needs it in `build.zig`.

The basic pattern is:

```zig
const dep = b.dependency("name", .{
    .target = target,
    .optimize = optimize,
});

exe.root_module.addImport("name", dep.module("name"));
```

Once you understand that pattern, Zig dependencies become much easier to read.

