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

# Syntax and source files

> The supported HCL subset and configuration loading rules.

A configuration is a directory of `*.hcl` files. Rivet loads the files directly in that directory, in sorted order, as one configuration. Subdirectories are not loaded, except as [modules](/guides/modules) you call explicitly, so assets such as templates and config files can live there.

HCL files must be regular UTF-8 files, not symlinks. All loaded HCL, including modules, can total at most 16 MiB.

## Blocks and attributes

Resources use a type and exactly one label:

```hcl
file "message" {
  path    = "/etc/rivet-message"
  content = "Hello\n"

  meta {
    description = "A managed message"
  }
}
```

There is no Terraform-style `resource "file" "message"` wrapper. Built-in root blocks are `file`, `package`, `user`, `group`, `group_membership`, `exec`, `service`, `timer`, `ssh_key`, `mount`, `module`, `variable`, `locals`, `output`, and `plugin`. Approved plugins can register additional resource type names.

Identifier labels start with an ASCII letter or underscore and continue with letters, digits, underscores, or hyphens. Resource labels also accept normalized absolute paths, such as `file "/etc/myapp/config.conf"`; reference them with `file["/etc/myapp/config.conf"]`. A path label does not supply the resource's `path` attribute. Module, variable, and output labels retain identifier rules. Labels are unique within their resource type; variables, locals, and outputs have their own namespaces. Duplicate declarations and attributes fail.

`locals` has no label. Resource child blocks, including `meta` and package provider blocks, are unlabelled and must be unique within the declaration. Unknown fields and child blocks are errors. Top-level attributes aren't allowed; put named values in `locals`.

HCL comments use `#`, `//`, or `/* ... */`. Strings use double quotes and escape sequences such as `\n`. Lists use square brackets; objects use braces with named entries.

[Agent](/operations/agent#settings) and [server](/operations/compile-service) configuration files use a different, literal-only format. Keep them outside your configuration directory.

## Plugin requirements

A `plugin "ALIAS"` block has exactly two attributes: literal string `source` and `version`. It checks that a matching plugin is installed and approved on this machine; it can't install or approve one. Duplicate requirements fail. Exact versions, `= VERSION`, and numeric `~> MAJOR.MINOR` or `~> MAJOR.MINOR.PATCH` constraints are supported.

```text
plugin "example" {
  source  = "example.com/rivet/example"
  version = "~> 1.0"
}
```

Plugin functions use `plugin::ALIAS::NAME(...)`. Service and package providers use `provider = "NAME"` and an unlabelled provider-specific child block. See [subprocess plugins](/contributing/plugins) for installation and complete examples.

## What expressions can do

Rivet supports most of the HCL expression language: numbers, strings, collections, operators, conditionals, `for` expressions, splats, interpolation, [functions](/language/functions), [heredocs and templates](/language/templates), [modules](/guides/modules), and [`count` and `for_each`](/language/expansion). Values come from [variables](/language/variables-and-outputs), [facts](/language/facts), and input files or [data hierarchies](/guides/data-hierarchy).

Everything is evaluated at compile time. Expressions can read files inside the configuration directory and render templates, but can't run commands, inspect the host, or download data. Remote modules, cloud file sources, and SOPS layers are fetched or decrypted by their own separate steps.

`resource("file")` and the other resource type names are valid as output and variable types, not as callable functions.

See [limitations](/reference/limitations#language) for unsupported constructs.