> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://rivet.chrisboulton.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://rivet.chrisboulton.com/_mcp/server.

# Modules

> Compose isolated configuration directories through typed arguments and explicit outputs.

A module is a directory of HCL files and assets that you call from another configuration. Each call gets its own variables, locals, and resources. A module sees only the arguments you pass it and the host's facts; it can't read its caller's variables or resources. Its caller can read only the module's declared outputs. File reads and templates inside a module resolve relative to the module's own directory.

## A reusable file module

Create `configuration/modules/file/main.hcl`:

**`modules/file/main.hcl`**

```hcl title="modules/file/main.hcl"
variable "path" {
  type     = string
  nullable = false
}

variable "text" {
  type    = string
  default = "hello\n"
}

file "config" {
  path    = var.path
  content = var.text
  mode    = "0644"
}

output "handle" {
  type  = resource("file")
  value = file.config
}
```

Call it from `configuration/main.hcl`:

```hcl
module "message" {
  source = "./modules/file"
  path   = "/etc/rivet-message"
  text   = "managed by a module\n"
}

output "message_path" {
  type  = string
  value = module.message.handle.path
}
```

The file's address is `module.message.file.config`, but the caller can't refer to it by that name; only declared outputs are visible. Using the `handle` output, as `message_path` does, carries the dependency along, so anything that uses it is ordered after the file.

For a complete checkout fixture with external inputs and multiple instances:

```sh
rivet init examples/modules
rivet validate examples/modules --vars-file examples/modules/inputs.yaml
rivet compile examples/modules --vars-file examples/modules/inputs.yaml \
  --facts examples/modules/target.json --out modules.bundle
rivet graph modules.bundle --format json
```

`target.json` is a generic baseline. Compile against facts from a real host before applying.

## Source directories and confinement

A local `source` is a literal relative path. A module can refer to sibling modules with `../`, but can't reach outside the configuration directory, or outside its package for [remote modules](/guides/remote-modules). Assets must be inside the module's own directory. `path.module` is the module's directory.

Like the root, a module loads only the `*.hcl` files directly in its directory.

## Ordering boundaries

Module metadata supports `depends_on`, `before`, `noop`, `tags`, literal `description`, and `notify`.

* `depends_on` gates every descendant behind the module's entry barrier.
* `before` orders later work after the module's completion barrier.
* A whole-module dependency waits for all descendants. A dependency on an exported resource handle waits for that resource and its prerequisites.
* Ordering works the same for nested and empty modules. Module boundaries are ordering points only; they don't do anything on the host.
* Module noop inherits with logical OR; children cannot turn it off. Tags inherit by set union.

Resources can also depend on or precede whole modules. `graph --format json` retains resource `order`/`edges` and adds all `nodes` and complete graph `module_edges`.

## Module notifications

A module may declare `meta { notify = [service.app] }`; a service or refresh-only exec may subscribe to a module. Every verified descendant change creates durable causal work before mutation. Delivery coalesces per target and waits for successful module completion, including required descendant refresh work. Partial failure preserves obligations for a later successful run. Noop creates no obligations; interrupted delivery remains at least once.

Whole modules cannot be refresh targets. Module `subscribe`, `timeout`, and `sensitive` metadata are unsupported. Notifying a descendant of the same source module creates a completion cycle; use internal resource notifications instead.

## Limits

All loaded HCL can total 16 MiB. Modules can nest 32 deep, and a configuration can have at most 1,024 module instances and 10,000 resources. Errors such as missing arguments, references to private resources, ownership conflicts, and cycles are reported before any asset is downloaded.