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

# What is Rivet?

> Configuration management for Linux hosts: compile a self-contained bundle, apply it, and recover cleanly from interruptions.

Rivet is a configuration management tool for Linux hosts. You describe the state you want in HCL: files, packages, users, services, timers, mounts. Rivet compiles that description into a **bundle**, one file holding the evaluated configuration and all the content it needs. Then it applies the bundle on the host.

What makes Rivet different:

* **Everything is evaluated before the host is touched.** Expressions, modules, templates, data hierarchies and SOPS decryption all run at compile time. The host receives finished desired state, so applying needs no access to your source, cloud storage, or credentials. Apt still needs its package repositories.
* **Every change is journalled before it starts.** If a run is interrupted by a crash, reboot, or dropped SSH connection, the next run sees what was in flight, re-inspects the host, and finishes the work. A service restart queued by a run that died still happens.
* **Undeclared properties are left alone.** Rivet manages only what you declare. If you don't set a file's mode, Rivet keeps whatever mode the file already has.

If you have used Puppet, the model will feel familiar. Facts describe a host, a compiler turns configuration plus facts into a catalog, and a runner converges the host toward it. Rivet differs in shipping the catalog and its file content together as one verified bundle, and in being a single Rust binary.

## A small example

```hcl
package "nginx" {}

file "status" {
  path    = "/etc/nginx/conf.d/status.conf"
  content = "server {\n  listen 127.0.0.1:8080;\n  location /status { stub_status; }\n}\n"

  meta {
    depends_on = [package.nginx]
    notify     = [service.nginx]
  }
}

service "nginx" {
  ensure    = "running"
  enabled   = true
  on_change = "reload"
}
```

Applying this installs nginx, writes the config file once the package exists, makes sure nginx is running and enabled, and reloads it whenever the config file changes. Applying it again changes nothing. If someone edits the config by hand, the next apply restores it and reloads nginx.

```sh
rivet facts --local > facts.json
rivet compile ./configuration --facts facts.json --out host.bundle
rivet plan host.bundle --local
sudo rivet apply host.bundle --local
```

[How it works](/how-it-works) explains what each of these steps does.

## Ways to run it

| Mode                                                          | Use it when                                                                                              |
| ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| [Local](/getting-started/quickstart)                          | You are trying Rivet out, or managing a single host.                                                     |
| [SSH from a controller](/operations/ssh)                      | You want to push changes from a laptop or CI to a few hosts without installing an agent.                 |
| [Agent with source releases](/operations/distribution)        | You want hosts to pull configuration from S3 or GCS on a schedule.                                       |
| [Agent with the compile service](/operations/compile-service) | You want compilation off the hosts, or want to classify hosts by verified cloud or certificate identity. |

All four use the same runner on the host. [Choosing how to run Rivet](/operations/modes) compares them in more detail.

## What it manages

| Resource                                        | Manages                                                                                              |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [File](/resources/file)                         | Files, directories, and symlinks, with ownership, modes, backups, and validation before replacement. |
| [Package](/resources/package)                   | Apt packages and bundled `.deb` archives, with versions, holds, and removal.                         |
| [User](/resources/user)                         | Local accounts, passwords, expiry, and home directories.                                             |
| [Group](/resources/group)                       | Local groups and GIDs.                                                                               |
| [Group membership](/resources/group-membership) | Supplementary group members, either added or managed as an exact list.                               |
| [Exec](/resources/exec)                         | Commands guarded by conditions, or run only when notified.                                           |
| [Service](/resources/service)                   | Systemd units: running, enabled, masked, restart or reload on change.                                |
| [Timer](/resources/timer)                       | Systemd timers and the oneshot services they run.                                                    |
| [SSH authorized key](/resources/ssh-key)        | Individual entries in `authorized_keys` files.                                                       |
| [Mount](/resources/mount)                       | Active mounts and their `/etc/fstab` entries.                                                        |

Approved [plugins](/contributing/plugins) can add resource types, service and package backends, and functions.

## Status

Rivet is experimental. Managed hosts must run Ubuntu 24.04 on x86_64 or ARM64 with systemd, and applying changes requires root. You can write and compile configuration, and drive hosts over SSH, from macOS or Linux. Bundle and journal formats can change between versions without migration. See [limitations](/reference/limitations) for what is not supported yet.

Start with [installation](/getting-started/installation) and [your first configuration](/getting-started/quickstart).