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

# Remote module sources

> Pin modules from Git or tar archives, fetch them with rivet init, and compile offline.

A [module](/guides/modules) `source` can point at a Git repository or a tar archive instead of a local directory. Rivet never fetches these during compilation. You run `rivet init` once to download and verify them, and commit the resulting lockfile, so every compilation uses exactly the same code.

Remote sources use one of these forms, with a real commit or digest in place of the placeholder:

```text
source = "git::https://example.org/config.git//modules/account?ref=<full-lowercase-commit>"
source = "git::ssh://git@example.org/config.git//modules/account?ref=<full-lowercase-commit>"
source = "archive::https://example.org/account.tar?sha256=<64-lowercase-hex-digits>"
```

* **Git** refs must be full 40- or 64-character lowercase commit IDs. Branches and tags aren't accepted, because they can move.
* **Archives** must be uncompressed tar files, pinned by SHA-256.
* A `//subdirectory` must stay inside the repository or archive.
* HTTPS URLs can't contain credentials. SSH URLs can include a username, but not a password. Authentication uses your normal Git and SSH setup, and credentials never reach the bundle.

`init` uses the installed `git` and `curl`. Git hooks, local file transport, submodules, interactive prompts, and your global Git configuration are disabled while fetching. Archives may contain only regular files and directories. Submodules, Git LFS, compressed archives, module registries, and version ranges aren't supported.

## Preparation workflow

After declaring the actual pinned sources in your configuration:

```sh
rivet init ./configuration
rivet validate ./configuration --vars-file inputs.yaml --facts facts.json
rivet compile ./configuration --vars-file inputs.yaml --facts facts.json --out host.bundle
```

`rivet init` downloads every remote module, including those used by other modules and those whose `count` is zero, into `.rivet/modules`, and writes `rivet.lock.json`. Commit the lockfile and add `.rivet/modules` to `.gitignore`. Each package's file-tree digest is checked before every compilation. `init` reuses cached packages that verify and re-downloads any that have been tampered with. If the lockfile or a package is missing or doesn't match, `validate` and `compile` fail until you run `init` again.

The bundle contains the evaluated result, so hosts never need access to module sources. Pinning a module doesn't make it safe: its resources run as root like any other configuration, so review it.

Each package can be at most 256 MiB, with at most 10,000 entries and paths up to 64 components deep. Each `git` or `curl` command has 60 seconds.