# !include

The `!include` function lets you load files — either local or remote — and insert their contents or specific values
directly into sections of your stack manifests.

The YAML standard provides [anchors and aliases](https://yaml.org/spec/1.2.2/#3222-anchors-and-aliases), that allow you
to reuse and reference pieces of your YAML file, making it more efficient and reducing duplication.

Atmos supports YAML anchors and aliases, but the biggest limitation is that they are only available within the file in
which they are defined. You cannot reuse anchors across different files.

The `!include` Atmos YAML function overcomes this limitation by allowing you to include the content or specific values
from different local and remote sources. The `!include` function also provides the following features:

- Supports local files with absolute and relative paths.

- Supports the remote protocols provided by the [`go-getter`](https://github.com/hashicorp/go-getter) library.

- Allows you to use [YQ](https://mikefarah.gitbook.io/yq) expressions to query and filter the content of the files to retrieve individual values.

- Determines the format based on file extensions. It supports files in JSON (`.json`), YAML (`.yaml`, `.yml`),
  and [HCL](https://github.com/hashicorp/hcl) (`.hcl`, `.tf`, `.tfvars`) formats, and automatically converts them into correct
  YAML structures (simple and complex types like maps and lists are supported).
  All other file extensions (including `.txt` or files without extensions) are returned as raw strings,
  allowing you to include text and [Markdown](https://www.markdownguide.org/) files as strings in Atmos manifests.

Atmos resolves the `!include` functions during the initial loading of YAML files from the local filesystem or remote sources,
injecting the contents of the referenced files directly into the current location.
Files are parsed based on their extension: JSON (`.json`), YAML (`.yaml`, `.yml`), HCL (`.hcl`, `.tf`, `.tfvars`)
are converted into the appropriate type (`boolean`, `map`, `list`, etc.), while other extensions return raw strings.

## Supported File Formats

With `!include` it's possible to import multiple different file formats into Atmos configurations. File parsing is determined by the file extension:

- **JSON** - Files with `.json` extension are parsed as JSON
- **YAML** - Files with `.yaml` or `.yml` extensions are parsed as YAML
- **HCL** - Files with `.hcl`, `.tf`, or `.tfvars` extensions are parsed as HCL
- **Text** - All other extensions (including `.txt` or no extension) are loaded as plain text

> **Note**
>
> File type detection is based on the file extension, not the content. For example, a `.txt` file containing JSON
> will be returned as a raw string. To force any file to be included as raw text regardless of extension,
> use the [`!include.raw`](./include.raw) function.
>
> **Important for URLs:** URLs that lack a file extension (like `https://api.github.com/meta`) will be treated as
> plain text. If you need to parse such URLs as JSON or YAML, ensure the URL ends with the appropriate extension
> (e.g., `.json`) or save the content to a local file with the correct extension first.

### URL Query Strings and Fragments

When including files from URLs with query strings or fragments, the extension detection ignores these URL components:

```yaml
# Extension is detected as .json (query string ignored)
vars: !include https://api.example.com/config.json?version=2&format=raw

# Extension is detected as .yaml (fragment ignored)
settings: !include https://example.com/settings.yaml#section1

# Extension is detected from the path (query/fragment ignored)
config: !include https://example.com/data.json?v=1#field
```

## Supported Sources

### Local Sources

The `!include` function supports the following local file sources. Atmos resolves local file paths using the following
strategies in order, finding the **first match** that points to an existing file:

1. **Absolute paths** — Used as-is with no resolution needed.
   ```yaml
   vars: !include /Users/me/Documents/vars.yaml
   ```

2. **Stack Manifest-relative paths (`./` or `../`)** — Paths that start with `./` or `../` are resolved relative to the
   directory containing the manifest file where the `!include` function is used. Atmos rewrites the path by joining
   it with the manifest's directory before checking if the file exists. For example, if the manifest is at
   `stacks/deploy/dev.yaml`, then `../config/vars.yaml` resolves to `stacks/config/vars.yaml`.

   ```yaml
   # Resolved relative to the directory of the current manifest file
   vars: !include ../config/vars.yaml
   settings: !include ./overrides.yaml
   ```

   > **Note**
   >
   > Use `./` or `../` prefixes when you want to explicitly reference files relative to the current manifest's
   > location. This is the most unambiguous way to include files that live near the manifest.

3. **Paths relative to `base_path`** — All other relative paths (those **without** a `./` or `../` prefix) are
   resolved relative to the [`base_path`](/cli/configuration#base-path) defined in `atmos.yaml`. This is the most
   common pattern for referencing shared configuration files (e.g., in a `config/` or `stacks/catalog/` directory)
   from any stack manifest, regardless of where that manifest is in the directory tree.

   ```yaml
   # Resolved relative to `base_path` in atmos.yaml (typically the repo root)
   vars: !include config/vars.json
   ```

   For example, given this `atmos.yaml`:

   ```yaml
   base_path: "./"
   ```

   The path `config/vars.json` in any manifest resolves to `<repo-root>/config/vars.json`.

### Remote Sources

To download remote files, Atmos uses [`go-getter`](https://github.com/hashicorp/go-getter)
(used by [Terraform](https://www.terraform.io/) for downloading modules) and supports the following protocols to download a single file:

- **http/https** - the file must be publicly accessible (not inside a private repository)
  ```yaml
  vars: !include https://raw.githubusercontent.com/org/repo/main/path/to/vars.yaml
  ```

- **github://** - GitHub URLs are automatically converted to raw content URLs

  ```yaml
  # Standard GitHub blob URL (automatically converted to raw URL)
  vars: !include https://github.com/org/repo/blob/main/path/to/vars.yaml

  # GitHub tree URL (automatically converted to raw URL)
  config: !include https://github.com/org/repo/tree/main/path/to/config.json

  # GitHub shorthand syntax
  settings: !include github://org/repo/main/path/to/settings.yaml

  # Already raw URLs work as-is (no conversion needed)
  data: !include https://raw.githubusercontent.com/org/repo/main/path/to/data.yaml
  ```

  > **Note**
  >
  > When using standard GitHub URLs (with `/blob/` or `/tree/`), Atmos automatically converts them to raw content URLs
  > (`raw.githubusercontent.com`) before downloading. This means you can copy URLs directly from GitHub's web interface
  > without manually converting them to raw format.
  >
  > If the URL doesn't include a branch/tag/commit reference, Atmos defaults to the `main` branch.

- **s3** (Amazon S3) - requires the correct AWS permissions and credentials configured
  ```yaml
  vars: !include s3::https://my-bucket.s3.amazonaws.com/path/to/vars.yaml
  ```

- **gcs** (Google Cloud Storage) - requires valid Google Cloud credentials
  ```yaml
  vars: !include gcs::gs://my-bucket/path/to/vars.yaml
  ```

- **scp/sftp** (SSH-based File Transfer) - requires SSH access to the remote server
  ```yaml
  vars: !include scp://user@remote-server:/path/to/vars.yaml
  settings: !include sftp://user@remote-server:/path/to/settings.yaml
  ```

- **oci** (Open Container Initiative)
  ```yaml
  vars: !include oci://ghcr.io/my-org/my-image:path/to/vars.yaml
  ```
  - The file must be exposed as part of the OCI image and exist as a layer in the image (not hidden inside layers)
  - The registry must support OCI artifact downloads (e.g., AWS ECR, Docker Hub, GHCR, GCR)

## Key Benefits of `!include`

The `!include` directive enables modular, reusable configuration patterns across all Atmos YAML files.
This has several important implications:

- **Modularization & Reuse**
  `!include` supports a [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) approach by allowing shared configuration fragments to be stored in local or remote
  files and reused across multiple stacks or components. You can use it in place of YAML anchors, which don't work across files.

- **Preprocessing for Inheritance**
  Includes are resolved _before_ Atmos processes stacks and components, enabling powerful [inheritance](/howto/inheritance) and deep-merging
  behaviors using fully expanded configuration data.

- **Adopting Existing Terraform/OpenTofu Root Modules as Atmos Components**
  If you're already managing your root modules using `.tfvars` files — for example, separate files for `dev`, `staging`,
  and `prod` — you can reference them directly in Atmos using `!include`. This makes it easy to adopt Atmos without
  having to translate all variables into Atmos stacks.

### Example: Referencing Different TFVAR Files Per Environment

For example, instead of rewriting existing `.tfvars` varfiles into inline YAML, Atmos lets you bring them in as-is into your [Stacks](/learn/stacks/).
You can continue managing your root modules as you always have, while gaining Atmos features like stack inheritance,
environment promotion, and deep-merging.

Let's say you already have environment-specific `.tfvars` files like:

- `config/dev.tfvars`
- `config/staging.tfvars`
- `config/prod.tfvars`

You can keep using these files in Atmos by referencing them in your stack configurations:

**File:** `stacks/org/dev/app.yaml`

```yaml
components:
  terraform:
    app:
      vars: !include config/dev.tfvars
```

**File:** `stacks/org/staging/app.yaml`

```yaml
components:
  terraform:
    app:
      vars: !include config/staging.tfvars
```

**File:** `stacks/org/prod/app.yaml`

```yaml
components:
  terraform:
    app:
      vars: !include config/prod.tfvars
```

This pattern allows you to plug Atmos into your existing Terraform/OpenTofu root modules with minimal changes — no need to
duplicate or reformat your varfiles. You also unlock additional capabilities like [listing all your stacks](/cli/commands/list/stacks)
and [components](/cli/commands/list/components), leveraging layered configurations, [stack inheritance with imports](/stacks/imports),
and consistent promotion of settings across environments.

## Usage

The `!include` function can be called with either one or two parameters:

```yaml
  # Download the file and inject the content directly into the current location in the YAML
  !include <file-path>

  # Download the file, filter the content using the YQ expression,
  # and inject the result directly into the current location in the YAML
  !include <file-path> <yq-expression>
```

## Arguments

- **`file-path`**

  Path to a local or remote file
- **`yq-expression`**
  (Optional) 
  [YQ](https://mikefarah.gitbook.io/yq)
   expression to retrieve individual values from the file

## Using YQ Expressions to retrieve individual values from files

To retrieve individual values from complex types such as maps and lists, or do any kind of filtering or querying,
you can utilize [YQ](https://mikefarah.gitbook.io/yq) expressions.

For example:

- Retrieve the first item from a list

```yaml
subnet_id1: !include <file-path> .private_subnet_ids[0]
```

- Read a key from a map

```yaml
username: !include <file-path> .config_map.username
```

For more details, review the following docs:

- [YQ Guide](https://mikefarah.gitbook.io/yq)
- [YQ Recipes](https://mikefarah.gitbook.io/yq/recipes)

## Handling File Paths and YQ Expressions with Spaces and Quotes

If you have spaces in the file names or YQ expressions, enclose the file paths and YQ expressions in double quotes
and use single quotes around the whole expression.

For example, on Windows:

```yaml
  vars:
    values: !include '"~/My Documents/dev/values.yaml"'
    config: !include '"~/My Documents/dev/config.json" "<yq-expression-with-spaces>"'
```

On macOS and Linux:

```yaml
  vars:
    values: !include './values.yaml "<yq-expression-with-spaces>"'
    description: !include '"component description.md"'
```

**Using YQ Expressions with Bracket Notation**

When a YQ expression needs double quotes inside bracket notation (for example, `["github-dependabot"]`), wrap the expression argument in single quotes while leaving the `!include` tag itself unquoted. This keeps the parser from splitting the expression into multiple arguments. The detailed guidance lives in the [!terraform.output documentation](/functions/yaml/terraform.output#handling-yq-expressions-with-bracket-notation-and-quotes), which applies here as well.

```yaml
vars:
  access_key: !include ./config.yaml '.security.users["github-dependabot"].access.key.id'
```

For paths that already require double quotes, put each argument in double quotes and wrap the entire arguments string in single quotes—`!include '"path with spaces.yaml" ".data[\"key\"]"'`—and see the linked documentation for more escaping techniques.

:::tip
`!include`, `!terraform.output`, and the other YAML functions share the same parser, so you only need to learn the quoting rules once.
:::

## Examples

**File:** `stack.yaml`

```yaml
components:
  terraform:
    my-component:
      vars:
        # Include a local file with the path relative to the current Atmos manifest
        values: !include ./values.yaml
        # Include a local file with the path relative to the current Atmos manifest and query the `vars.ipv4_primary_cidr_block` value from the file using YQ
        ipv4_primary_cidr_block: !include ./vpc_config.yaml .vars.ipv4_primary_cidr_block
        # Include a local file relative to the `base_path` setting in `atmos.yaml`
        vpc_defaults: !include stacks/catalog/vpc/defaults.yaml
        # Include a local file in HCL format
        hcl_values: !include ./values.hcl
        # Include a local varfile in HCL format
        tfvars_values: !include ../components/terraform/vpc/vpc.tfvars
        # Include a local Markdown file
        description: !include ./description.md
        # Include a local text file
        text: !include a.txt
        # Include a local text file with spaces in the file name
        text2: !include '"my config.txt"'
        # Include a local text file on Windows with spaces in the file name, and get the `config.tests` value from the file
        tests: !include '"~/My Documents/dev/tests.yaml" .config.tests'
        # Download and include a remote YAML file using HTTPS protocol, and query the `vars` section from the file
        region_values: !include https://raw.githubusercontent.com/cloudposse/atmos/refs/heads/main/examples/quick-start-advanced/stacks/mixins/region/us-east-2.yaml .vars
        # Download from GitHub using standard GitHub URL (automatically converted to raw URL)
        github_vars: !include https://github.com/cloudposse/atmos/blob/main/examples/quick-start-advanced/stacks/mixins/region/us-east-2.yaml .vars
        # Download using GitHub shorthand syntax
        github_config: !include github://cloudposse/atmos/main/examples/quick-start-advanced/atmos.yaml
        # Download and include a remote JSON file from a URL with .json extension
        # Note: For URLs without extensions, save locally first or use a URL with .json extension
        api_config: !include ./github-meta.json .api
```

**File:** `stack.yaml`

```yaml
# The `config` folder is relative to the `base_path` setting in `atmos.yaml`
import: !include config/import.yaml

# Download the remote file using `go-getter` and assign the `components.terraform.component-1.settings` section
# from the file to the `settings` section in the current stack
settings: !include https://raw.githubusercontent.com/cloudposse/atmos/main/tests/fixtures/scenarios/stack-templates-2/stacks/deploy/nonprod.yaml .components.terraform.component-1.settings

components:
  terraform:
    component-1:
      vars:
        # The `config` folder is relative to the `base_path` setting in `atmos.yaml`
        string_var: !include config/vars.json .string_var
        boolean_var: !include config/vars.yaml .boolean_var
        list_var: !include config/vars.tfvars .list_var
        map_var: !include config/vars.tfvars .map_var

    component-2:
      vars: !include config/vars.tfvars

    component-3:
      vars: !include config/vars.json

    component-4:
      vars: !include config/vars.yaml
```
