> 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.

# Resources and relationships

> Order work and deliver refreshes after verified changes.

Rivet builds a directed graph of prerequisites and dependents. Execution follows a deterministic topological order, inspecting each resource immediately before its work.

## Explicit ordering

```hcl
file "directory" {
  path   = "/var/lib/app"
  ensure = "directory"
}

file "config" {
  path    = "/var/lib/app/config"
  content = "enabled\n"
  meta { depends_on = [file.directory] }
}
```

`depends_on` lists prerequisites. `before` lists resources that must follow this resource. Both accept lists of handles, never string addresses. Whole-module references and expanded module families are also accepted for ordering. `before` creates a forward edge without a reverse expression edge.

Declare explicit absent states for removal. Declared file descendants automatically precede absent ancestors; mount removal precedes an absent mountpoint directory; key removal precedes removal of its managed user. Other absent resources do not automatically reverse dependencies, so account and group removal still needs explicit ordering.

## Implicit ordering

References to handles or exported properties carry dependency provenance through locals and interpolation. Present users depend on managed primary and supplementary groups even when the relationship uses a literal group name or explicit GID. Group memberships depend on managed groups and listed users.

Services with automatic daemon reload depend on declared service-definition producers. Declared file ancestors, managed file owner and group identities, timer accounts, authorized-key users, mountpoint directories, and files beneath managed mounts also derive ordering. These resource-specific rules do not imply a dependency for every equal string.

Whole-module dependencies wait for completion of all descendants; exported resource handles retain their narrower resource dependency. See [module boundaries and notifications](/guides/modules).

## Notifications

```hcl
file "config" {
  path    = "/etc/app-config"
  content = "enabled\n"
  meta { notify = [service.app] }
}

service "app" {
  name      = "example-app"
  ensure    = "running"
  on_change = "restart"
}
```

`notify` orders the declaring source before each refresh target. The inverse spelling is `subscribe` on the target: `meta { subscribe = [file.config] }`. Targets must be services or exec resources with `refresh_only = true`.

A dependency alone does not trigger a refresh. A notification becomes deliverable after a verified source change. Multiple sources coalesce into one target delivery after its prerequisites succeed. Modules can notify targets, and refresh-capable resources can subscribe to whole modules; delivery waits for successful module completion, including descendant refresh work. Accepted unchanged exec exits do not create new notifications.

Notifications are durable causal work. Recovery can deliver a refresh again after interrupted acknowledgement; exactly-once execution is not promised. [Recovery](/reference/recovery) explains how obsolete obligations are handled.

## Failure and noop behavior

A failed prerequisite blocks dependent resources while unrelated resources continue. A noop prerequisite that would change defers dependent predictions/work. A converged noop prerequisite permits dependent work.

Missing references, invalid refresh targets, physical ownership conflicts, and graph cycles fail before the bundle is published. Inspect explained edges with `rivet graph host.bundle --format json`.