# Version Files

`version.files` declares which files carry managed versions. [`atmos version track apply`](/cli/commands/version/track/apply) rewrites those files from the lock file, and [`verify`](/cli/commands/version/track/verify) fails when they drift.

## Configuration

**File:** `atmos.yaml`

```yaml
version:
  files:
    - manager: github-actions
      paths:
        - .github/workflows/*.yaml
        - .github/workflows/*.yml

    - manager: marker
      paths:
        - Dockerfile
        - scripts/**/*.sh

    - manager: json
      paths:
        - agent-skills/.claude-plugin/plugin.json
        - .claude-plugin/marketplace.json
      options:
        set:
          - path: version
            from: atmos

    - manager: yaml
      paths:
        - charts/*/values.yaml
      options:
        set:
          - path: version
            from: cli
            format: '{{ trimPrefix "v" .Version }}'

    - manager: template
      paths:
        - "**/*.tmpl"
```

When `version.files` is omitted, managers with default paths run over those defaults. An explicit `files: []` is different from omitting the key: it means "manage zero files," and suppresses the default-path fallback.

`version.files`, like every other `atmos.yaml` setting, follows [Atmos's standard import precedence](/cli/configuration/imports#merge-order): the main `atmos.yaml`'s own value always wins over an [`import:`](/cli/configuration/imports) fragment or `atmos.d/` file that also sets `version.files`, including `files: []`. An imported fragment can only supply `version.files` when the main file doesn't mention the key at all — it can never override or clear a list the main file already declares.

## Managers

- **`github-actions`**
  Rewrites 
  `uses:`
   refs in workflow files by matching 
  `owner/repo`
   packages.
- **`marker`**
  Rewrites version tokens on lines annotated with 
  `atmos:version`
   comments.
- **`json`**
  Writes locked values into JSON files at configured field paths, preserving formatting and key order.
- **`yaml`**
  Writes locked values into YAML files at configured field paths, preserving comments, anchors, and key order.
- **`template`**
  Renders 
  `*.tmpl`
   source files to sibling files using the 
  `.version`
   context.

## Updating Dockerfiles

Annotate the line to update with an `atmos:version` comment. The `marker` manager rewrites the version token in place from the lock file, matching entries by name. Given this `atmos.yaml`:

**File:** `atmos.yaml`

```yaml
version:
  dependencies:
    opentofu:
      ecosystem: toolchain
      datasource: toolchain
      package: opentofu
      desired: "~1.12"

    terraform:
      ecosystem: toolchain
      datasource: toolchain
      package: terraform
      desired: "~1.15"

  files:
    - manager: marker
      paths:
        - Dockerfile
```

`atmos version track apply prod` keeps annotated lines in sync with the locked versions:

### Single Tool

**File:** `Dockerfile`

```dockerfile
# atmos:version opentofu
ENV TOFU_VERSION=1.12.4
```

### Multiple Tools

A file can track more than one tool — each just needs its own marker line:

**File:** `Dockerfile`

```dockerfile
# atmos:version opentofu
ENV TOFU_VERSION=1.12.4

# atmos:version terraform
ENV TERRAFORM_VERSION=1.15.6
```

### YAML

The same annotation works in any commented format — the manager rewrites whatever token it finds on the marked line, not just Dockerfile `ENV` statements:

**File:** `versions.yaml`

```yaml
tofu_version: 1.12.4 # atmos:version opentofu
```

### Custom Match Pattern

Use `match=` when the default token detection is ambiguous, for example a version-shaped path segment appearing before the actual version. A **trailing** comment marks its own line:

**File:** `Dockerfile`

```dockerfile
RUN curl -fsSL https://releases.hashicorp.com/terraform/1.15.6/terraform_1.15.6_linux_amd64.zip # atmos:version terraform match=terraform_([0-9.]+)_linux
```

A **standalone** comment on the preceding line marks the next non-blank, non-comment line instead:

**File:** `Dockerfile`

```dockerfile
# atmos:version terraform match=terraform_([0-9.]+)_linux
RUN curl -fsSL https://releases.hashicorp.com/terraform/1.15.6/terraform_1.15.6_linux_amd64.zip
```

## Updating JSON Files

The `json` manager writes locked values into JSON files at configured field paths, using [sjson](https://github.com/tidwall/sjson)/[gjson](https://github.com/tidwall/gjson) dot-path syntax. Unlike a full JSON parse and re-serialize, `sjson` patches only the targeted field and leaves the rest of the file's bytes — formatting, key order, whitespace — untouched.

**File:** `atmos.yaml`

```yaml
version:
  dependencies:
    atmos:
      ecosystem: github/actions
      datasource: github-releases
      provider: github
      package: cloudposse/atmos
      desired: "~1.160"

  files:
    - manager: json
      paths:
        - agent-skills/.claude-plugin/plugin.json
      options:
        set:
          - path: version
            from: atmos
```

`atmos version track apply prod` writes the resolved value at the configured path:

### Single Field

**File:** `agent-skills/.claude-plugin/plugin.json`

```json
{
  "name": "atmos",
  "version": "1.160.0",
  "license": "Apache-2.0"
}
```

Only the `version` value's bytes change — every other key, its ordering, and any unusual spacing in the file is preserved exactly.

### Multiple Fields

A file can have more than one managed field — each just needs its own `set` entry, and a rule can list more than one target file:

**File:** `atmos.yaml`

```yaml
files:
    - manager: json
      paths:
        - package.json
      options:
        set:
          - path: version
            from: cli
          - path: engines.node
            from: node
```

**File:** `package.json`

```json
{
  "name": "example",
  "version": "2.5.0",
  "engines": {
    "node": "20.11.0"
  }
}
```

### Reshaping the Value

A dependency sourced from `github-releases`/`github-tags` locks the raw git tag (e.g. `v2.5.0`). When a target field needs a different shape, add `format` to the `set` entry: a Go template (Sprig plus Atmos's template functions) rendered against the resolved version, whose output replaces the verbatim value:

**File:** `atmos.yaml`

```yaml
files:
    - manager: json
      paths:
        - package.json
      options:
        set:
          - path: version
            from: cli
            format: '{{ trimPrefix "v" .Version }}'
```

**File:** `package.json`

```json
{
  "name": "example",
  "version": "2.5.0"
}
```

Without `format`, the same rule would write `"version": "v2.5.0"` verbatim.

`path` follows sjson/gjson dot syntax: dots nest into objects, a bare number indexes into an array, and a literal dot inside a key name is escaped as `\.`. `path` is always a YAML string — quote numeric segments (`path: "0"`), or the value decodes as a YAML integer and fails validation.

`format` is optional. When omitted, the resolved value is written verbatim (today's default behavior). When set, it's a Go template rendered against the resolved version — `.Version` (the human-readable version), `.Digest`, and `.Pin` are all available in the template context — and the rendered string is written instead. Any string function from [Sprig](https://masterminds.github.io/sprig/) works, e.g. `trimPrefix`, `trimSuffix`, `replace`, or `regexReplaceAll`.

A simple `path` (no wildcards) that doesn't exist yet in the file is created rather than rejected, so double-check `path` for typos — a misspelled path silently adds a new field instead of updating the intended one. Wildcard/query paths (`items.#.version`, `*`, `?`, `@`) update every matching location when the path resolves against the current document, but error instead of silently doing nothing when it resolves to nothing — for example, an empty array or a missing parent key.

A few configurations are rejected outright rather than risking silent data loss:

- **Array-append paths** (any `-1` segment) — there's no way to tell "already applied" from "not yet applied" by reading the array back, so every `apply` would append another element forever.
- **A `path` whose current value is an object or array** — writing a scalar there would silently discard the whole subtree. Target the specific field inside it instead (`engines.node`, not `engines`).
- **Two `set` entries targeting the same `path`** — the second write would otherwise silently discard the first.
- **A `format` template that fails to parse or execute** (a syntax error, or a reference to a field that doesn't exist) — rejected outright rather than writing garbage or an empty string.

## Updating YAML Files

The `yaml` manager writes locked values into YAML files at configured field paths, using the same format-preserving editor behind [`atmos config set`](/cli/commands/config/config-set) and [`atmos stack set`](/cli/commands/stack/stack-set). It edits the document via a targeted assignment rather than a full unmarshal/remarshal, so comments, anchors and aliases, and key order on untouched fields survive the write.

**File:** `atmos.yaml`

```yaml
version:
  dependencies:
    cli:
      ecosystem: github/releases
      datasource: github-releases
      provider: github
      package: cli/cli
      desired: "~2"

  files:
    - manager: yaml
      paths:
        - charts/*/values.yaml
      options:
        set:
          - path: version
            from: cli
            format: '{{ trimPrefix "v" .Version }}'
```

`atmos version track apply` rewrites the configured field and leaves everything else — comments, anchors, unrelated keys — untouched:

**File:** `charts/example/values.yaml`

```yaml
# Chart values.
image:
  repository: example
version: 2.50.0 # managed by atmos version track
```

`path` uses the same dot-notation as `atmos config set`/`atmos stack set`: dots nest into maps, `[N]` indexes into a sequence (e.g. `sources[0].version`), and a key that isn't a simple identifier is quoted (`metadata."weird.key"`). This differs from the `json` manager's sjson/gjson dialect — the two managers don't share path syntax.

`format` works exactly as it does for the `json` manager: an optional Go template rendered against the resolved version (`.Version`, `.Digest`, `.Pin`), with the rendered string written instead of the verbatim value. See [Sprig](https://masterminds.github.io/sprig/) for the available string functions.

A simple `path` that doesn't exist yet in the document is created rather than rejected. A `path` whose current value is a map or list is rejected rather than silently replaced with a scalar — target the specific field inside it instead.

Because the editor re-encodes the document, indentation is normalized to the file's own detected width rather than preserved byte-for-byte the way the `json` manager's sjson patch is — the practical difference shows up only in edge cases (unusual mixed indentation, some flow-style collections), not in ordinary block-style YAML.

## Updating GitHub Action Workflows

The `github-actions` manager rewrites `uses:` refs in workflow files, matching entries by `owner/repo` package.

### Version Bump

Add a dependency for the action and register the manager:

**File:** `atmos.yaml`

```yaml
version:
  dependencies:
    checkout:
      ecosystem: github/actions
      datasource: github-tags
      provider: github
      package: actions/checkout
      desired: "v6"

  files:
    - manager: github-actions
      paths:
        - .github/workflows/*.yaml
```

`atmos version track apply prod` rewrites the matching `uses:` line to the locked version:

**File:** `.github/workflows/ci.yaml`

```yaml
steps:
  - uses: actions/checkout@v6
```

### Pinned to SHA

Set `update.pin: sha` to pin third-party actions to their immutable commit SHA instead — Atmos writes the SHA with the human-readable version as a trailing comment, matching the Renovate/Dependabot convention:

**File:** `atmos.yaml`

```yaml
version:
  dependencies:
    checkout:
      ecosystem: github/actions
      datasource: github-tags
      provider: github
      package: actions/checkout
      desired: "v6"
      update:
        pin: sha
```

**File:** `.github/workflows/ci.yaml`

```yaml
steps:
  - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
```

## Examples

```shell
atmos version track apply prod
atmos version track apply prod --check
atmos version track apply prod --manager=github-actions
```
