# Vendor Configuration

The `vendor` section in `atmos.yaml` configures how Atmos discovers and processes vendor manifest files for dependency management.

## Configuration

**File:** `atmos.yaml`

```yaml
vendor:
  # Path to vendor manifest file or directory
  base_path: vendor.yaml

  # Concurrent downloads and update checks (edition-aware default)
  max_concurrency: 4

  # Configure output format for vendor list command
  list:
    format: table
    columns:
      - name: Component
        value: "{{ .component }}"
      - name: Version
        value: "{{ .version }}"
      - name: Source
        value: "{{ .source }}"

  # Global retry configuration for vendor operations (optional)
  retry:
    max_attempts: 3
    initial_delay: 2s
    max_delay: 30s
    backoff_strategy: exponential

  # Path to the vendor lock file (optional)
  lock_file: vendor.lock.yaml

  # How `atmos vendor pull` reacts to vendor.lock.yaml drift (optional)
  lock:
    enforcement: warn
```

## Configuration Reference

- **`base_path`**

  Path to the vendor manifest file or directory containing vendor files. Can be a single `vendor.yaml` file or a directory containing multiple `.yaml` files.

  When a directory is specified, all `.yaml` files in the directory are processed in lexicographical order.

  **Default:** `vendor.yaml`

  Examples:
  - `vendor.yaml` - Single manifest file
  - `./vendor.yaml` - Explicit relative path
  - `vendor/` - Directory containing multiple manifests
- **`list.format`**

  Output format for the `atmos vendor list` command.

  **Valid values:** `table`, `json`, `csv`
  **Default:** `table`
- **`list.columns`**

  Custom column definitions for table output. Each column has a `name` (header) and `value` (Go template expression).

  Available template variables:
  - `{{ .component }}` - Component name
  - `{{ .source }}` - Source URL
  - `{{ .version }}` - Version tag
  - `{{ .targets }}` - Target paths
  - `{{ .tags }}` - Associated tags
- **`retry`**

  Global retry configuration for vendor operations. These settings apply to all vendor sources unless overridden at the source level.

  Retry is useful for handling transient network errors, rate limiting, and other temporary failures when downloading from remote repositories.
  - **`retry.max_attempts`**
    Maximum number of retry attempts. 
    **Default:**
     
    `3`
  - **`retry.initial_delay`**
    Initial delay before the first retry. 
    **Default:**
     
    `2s`
  - **`retry.max_delay`**
    Maximum delay between retries. 
    **Default:**
     
    `30s`
  - **`retry.backoff_strategy`**
    Strategy for increasing delay between retries. 
    **Values:**
     
    `exponential`
    , 
    `linear`
    , 
    `constant`
    . 
    **Default:**
     
    `exponential`
  - **`retry.multiplier`**
    Multiplier for exponential backoff. 
    **Default:**
     
    `2.0`
  - **`retry.random_jitter`**
    Random jitter factor (0.0-1.0) to add randomness to delays. 
    **Default:**
     
    `0.1`
  - **`retry.max_elapsed_time`**
    Maximum total time for all retry attempts. 
    **Default:**
     
    `5m`
- **`lock_file`**

  The vendor lock file. It records a per-file SHA-256 receipt for every artifact vendored
  through `vendor.yaml` or `component.yaml`. The `atmos vendor verify` command checks
  this file for drift; `atmos vendor pull` and `atmos vendor update --pull`
  write to it.

  **Default:** `vendor.lock.yaml`
- **`lock.enforcement`**

  How `atmos vendor pull` reacts when a package's on-disk state no longer matches its
  `vendor.lock.yaml` receipt.

  When the receipt matches the declaration and all its recorded files are absent, Atmos
  treats the package as uninstalled and reinstalls it without a drift warning, including
  under `strict`. This supports `vendor clean` followed by `vendor pull`. Partially missing
  or modified files and changed declarations still use the enforcement policy below.

  **Valid values:**
  - `warn` — re-fetch the drifted package and print one warning per package naming why it drifted.
  - `silent` — re-fetch the drifted package with no reporting.
  - `strict` — refuse to run (before any fetch/copy/write) when a drifted package is found and
    `--refresh-lock` was not explicitly passed, naming every drifted package and its reason.
  **Default:** `warn`

  Override per invocation with `--lock-enforcement <strict|warn|silent>` on `atmos vendor pull`
  or `atmos vendor update --pull`.

## Concurrency

`vendor.max_concurrency` sets the maximum number of simultaneous downloads and
preparation jobs for [`vendor pull`](/cli/commands/vendor/pull), and upstream checks
for [`vendor update`](/cli/commands/vendor/vendor-update). The pull phase of
`vendor update --pull` uses the same value.

Precedence is **explicit `--max-concurrency` flag → `ATMOS_VENDOR_MAX_CONCURRENCY`
environment variable → merged configuration → edition-aware default**. Values
must be positive integers; explicit zero, negative, and malformed values fail
before vendoring begins.

| Edition pin | Default workers |
| :-- | --: |
| Unpinned | 4 |
| Before `2026-09-15` | 1 |
| On or after `2026-09-15` | 4 |

An explicit value overrides the edition pin. Partial dates follow the existing
[edition rules](/cli/configuration/edition): `"2026-08"` ends on August 31 and keeps
one worker; `"2026-09"` includes the September change and uses four.

```shell
atmos vendor pull --max-concurrency 8
ATMOS_VENDOR_MAX_CONCURRENCY=2 atmos vendor update --check
atmos vendor update --pull --max-concurrency 4
```

Downloads and preparation overlap. Destination copying and lock receipt updates
follow declaration order, including component sources before their mixins. Local
sources are staged after preceding writes, so they observe those files. At most
twice the worker count may be downloading or waiting to be installed. One worker
preserves serial execution.

All editions receive the progress display. Active rows show the current phase,
with byte counts when the download backend provides them. A **ready** package is
waiting for its turn to install; success appears only after files and receipts
are written. Completed results remain visible. CI and redirected output use plain
result lines on stderr, leaving structured update output on stdout intact.

Concurrent vendoring operations coordinate destination writes and receipts with
advisory locks. A failed package does not undo packages already installed. On
interruption, Atmos cancels pending work, cleans temporary downloads, and lets an
already-started materialization finish before releasing its locks.

## Component Updater Configuration

The `vendor.update` and `vendor.ci` sections configure `atmos vendor update --pull-request` — see
Native Pull Requests for Vendored Component Updates
for the full workflow and a worked example.

**File:** `atmos.yaml`

```yaml
vendor:
  update:
    execution:
      mode: current # or "worktree"
    batching:
      mode: scope # the only supported value today
    groups:
      platform:
        include: ["terraform/vpc", "terraform/eks/*"]
        exclude: ["terraform/eks/legacy"]
  ci:
    pull_request:
      provider: github
      base_branch: main
      branch_prefix: atmos/component-updater
      title: "chore(components): update {{ .scope.name }}"
      # body left unset here to use the default: the Atmos CI badge, a one-line explanation, and
      # {{ .updates | markdownTable }} -- set your own template to replace it entirely.
      labels: [component-update]
      draft: false
      reviewers: []
      assignees: []
    summary:
      enabled: true
```

- **`update.execution.mode`**

  The default, `current`, runs the whole cycle — discover, branch, commit, push — in the
  invoking checkout. The `worktree` mode runs it in an isolated linked Git worktree instead.
  The invoking checkout stays untouched, which helps when other steps in the same job need an
  unmodified checkout.
- **`update.batching.mode`**
  The only supported value is 
  `scope`
  : one branch and one PR for the whole update run. Per-component batching (one PR per updated component) isn't implemented yet.
- **`update.groups.<name>`**

  Selects components for `--group <name>`. Each group has `include` and optional `exclude` glob
  lists against component paths; exclusions win.
- **`ci.pull_request.provider`**
  Pull request provider. 
  **Valid values:**
   
  `github`
  , 
  `azuredevops`
  . 
  **Default:**
   
  `github`
  .
- **`ci.pull_request.base_branch`**
  Base branch for the pull request. 
  **Default:**
   the remote's advertised default branch.
- **`ci.pull_request.branch_prefix`**
  Prefix for the deterministic branch name. 
  **Default:**
   
  `atmos/component-updater`
  .
- **`ci.pull_request.title` / `ci.pull_request.body`**

  Go templates rendered with `.scope.name` and `.updates` (see `markdownTable` in the example
  above). **Title default:** `"chore(components): update {{ .scope.name }}"`. **Body default:**
  the Atmos CI badge, a one-line "Automated by `atmos vendor update --pull-request`" note, and
  `{{ .updates | markdownTable }}` — not just the bare table on its own.
- **`ci.pull_request.labels` / `.reviewers` / `.assignees`**

  Atmos applies these additively on every reconciliation. **Default label:** `[component-update]`.
  Azure DevOps pull requests have no assignee concept — setting `assignees` with
  `provider: azuredevops` fails with an error instead of silently dropping it; use `reviewers`
  there instead. With `provider: azuredevops`, each `reviewers` entry is a display name, account
  name, or email — Atmos resolves it to the individual it identifies. Only individuals are
  supported today, not groups.
- **`ci.pull_request.draft`**
  Create the pull request as a draft. 
  **Default:**
   
  `false`
  .
- **`ci.pull_request.organization` / `.project` / `.repository`**

  Required when `provider: azuredevops`. Azure DevOps addresses a repository with three
  segments — organization, project, and repository — instead of GitHub's owner/repository pair
  derived from the Git remote.
- **`ci.summary.enabled`**
  Whether to write a GitHub Actions step summary. 
  **Default:**
   
  `true`
  .

:::note
A default `GITHUB_TOKEN` won't trigger downstream `on: pull_request`/`on: push` Actions workflows.
Pair the Component Updater with the [`github/sts`](/cli/configuration/auth#github-sts-atmos-pro)
auth integration to get a token that does. See
`atmos vendor update`'s token precedence notes for details.
:::

:::note
The `azuredevops` provider authenticates with a personal access token in the
`AZURE_DEVOPS_EXT_PAT` environment variable, used as HTTP Basic auth with an empty username. The
token needs Code (Read & Write) permission on the target project.

```yaml
vendor:
  ci:
    pull_request:
      provider: azuredevops
      organization: my-org
      project: my-project
      repository: my-repo
```

:::

## Vendor Manifest Structure

The vendor manifest file defines external dependencies to pull into your project:

**File:** `vendor.yaml`

```yaml
apiVersion: atmos/v1
kind: AtmosVendorConfig
metadata:
  name: my-project-vendor
  description: Vendor dependencies for my project
spec:
  imports:
    - vendor/common.yaml
  sources:
    - component: vpc
      source: github.com/cloudposse/terraform-aws-vpc.git//src?ref={{.Version}}
      version: 1.0.0
      targets:
        - components/terraform/vpc

    - component: eks
      source: github.com/cloudposse/terraform-aws-eks-cluster.git?ref={{.Version}}
      version: 2.0.0
      targets:
        - components/terraform/eks
      included_paths:
        - "**/*.tf"
      excluded_paths:
        - "examples/**"
```

## Multiple Manifest Files

You can organize vendor configurations across multiple files:

```
vendor/
├── aws.yaml        # AWS-related components
├── kubernetes.yaml # Kubernetes components
└── common.yaml     # Shared dependencies
```

**File:** `atmos.yaml`

```yaml
vendor:
  base_path: vendor/
```

Atmos processes files in alphabetical order: `aws.yaml`, then `common.yaml`, then `kubernetes.yaml`.

## Related Commands

## Try It

Explore a working example that demonstrates vendor configuration.

## Related

- [Vendor Configuration Reference](/vendor/vendor-config)
