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

# Service

> Select a service backend and manage activity, supported properties, and durable refresh actions.

`service` manages whether a service is running, enabled, and masked, and how it reacts to notifications. Systemd is the built-in backend; [plugins](#plugin-providers) can add others. This example names systemd explicitly:

```hcl
service "app" {
  provider      = "systemd"
  name          = "example-app"
  ensure        = "running"
  enabled       = true
  masked        = false
  on_change     = "reload_or_restart"
  daemon_reload = "auto"
}
```

| Attribute       | Default                                                  | Behavior                                                                                                                |
| --------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `provider`      | `"auto"`                                                 | Select a registered backend, or resolve one from target capabilities and declared priorities at compilation.            |
| `name`          | Label                                                    | Normalized by the selected backend. Systemd adds `.service` and rejects paths, option-like names, and other unit types. |
| `ensure`        | Unmanaged                                                | `running` or `stopped`; null or omission leaves activity unmanaged.                                                     |
| `state`         | Alias                                                    | Legacy spelling of ensure; cannot supply both.                                                                          |
| `enabled`       | Unmanaged                                                | Independent enablement boolean; rejected if the selected backend does not support it.                                   |
| `masked`        | Unmanaged                                                | Independent mask boolean; rejected if the selected backend does not support it.                                         |
| `on_change`     | `"restart"` if supported, else `"none"`                  | Backend-supported choice of `restart`, strict `reload`, `reload_or_restart`, or `none`.                                 |
| `daemon_reload` | `"auto"` when a definition action exists, else `"never"` | `auto` or `never`; explicit `auto` is rejected without backend support.                                                 |

Null optional fields follow omission and default behavior. `stopped` means inactive; it does not delete, disable, or mask the unit. There is no service `absent` state.

## Systemd convergence

Unmasking precedes enable/start; stop/disable precede masking. A masked unit needs `masked = false` before it can be started or enabled. Enabling static, generated, or transient units fails.

Missing, malformed, transitional, and unsupported states fail instead of being treated as absent. Canonical unit identities detect alias ownership conflicts, including a fresh check after definition changes. Default budget: two minutes. Systemd requires `service.systemd.v1`; other backends declare their required capabilities.

## Refresh policy

`reload` is strict: failed or unsupported reload does not silently become a restart. Choose `reload_or_restart` if you want that fallback. `none` consumes notification work without a service mutation.

An inactive or explicitly stopped unit consumes refreshes without starting. A verified initial start consumes pending config refreshes without a redundant restart. Refresh is separate from ordinary desired-state convergence and has its own deadline.

Use `meta { subscribe = [file.config] }` or `notify` on the source to request refresh. Dependency ordering alone is insufficient.

## Systemd daemon reload barrier

With `auto`, managed `.service` files and `.service.d/*.conf` files beneath `/etc/systemd/system`, `/usr/lib/systemd/system`, and `/lib/systemd/system` precede service work. Changes coalesce into one journaled systemd daemon-reload barrier. Systemd-reported stale definitions can also request it.

This is a shared prerequisite action, separately reported from service restart/reload. `never` disables the automatic barrier. Automatic reload also requires `refresh.journal.v1`.

Refresh intent and outgoing causal obligations are durable. Interruption can lead to repeated delivery; [recovery](/reference/recovery) explains the limits.

## Plugin providers

Approved [subprocess plugins](/contributing/plugins#service-and-package-providers) can add backends with `provider = "NAME"` and a matching unlabelled child block for typed options. A child block for another provider fails validation. The normalized options, provider schema version, and implementation identity are pinned into the catalog and recovery digests.

`provider = "auto"` chooses the applicable backend with the highest declared priority using the compilation target's capabilities. A tie or no applicable backend fails. With only built-ins installed, systemd is selected when its capability is available. Use an explicit provider when selection must remain fixed as installations change.

Backends declare supported fields, refresh modes, capabilities, normalized identity, physical ownership, affected paths, and optional shared definition actions. Rivet retains property comparisons, verification, notification coalescing, startup refresh consumption, and reporting. Omitted properties remain unmanaged; unsupported requested properties are rejected. Plugin definition actions use the same durable shared-action mechanism as systemd's barrier.

To write a backend, see the [SDK guide](/contributing/plugins#service-and-package-providers).