# !store

The `!store` YAML function allows reading the values from a remote [store](/cli/configuration/stores)
(e.g. SSM Parameter Store, Artifactory, Redis, etc.) for an Atmos component in a stack into Atmos stack manifests.

## Usage

The `!store` function can be called with either two, three, or four parameters, and optionally a default value and
a [YQ](https://mikefarah.gitbook.io/yq) query expression:

```yaml
  !store <store_name> <stack> <component> <key> | default <default-value> | query <yq-expression>
```

Usage examples:

```yaml
  # Get the `key` from the store of a `component` in the current stack
  !store <store_name> <component> <key>

  # Get the `key` from the store of a `component` in the current stack,
  # and retrieve an individual value from the result using the YQ expression
  !store <store_name> <component> <key> | query <yq-expression>

  # Get the `key` from the store of a `component` in a different stack
  !store <store_name> <stack> <component> <key>

  # Get the `key` from the store of a `component` in a different stack,
  # and retrieve an individual value from the result using the YQ expression
  !store <store_name> <stack> <component> <key> | query <yq-expression>

  # Get the `key` from the store of a `component` in a different stack, with a default value
  !store <store_name> <stack> <component> <key> | default <default-value>
```

## Arguments

- **`store_name`**
  The name of the store to read from (as defined in the 
  `atmos.yaml`
   file)
- **`stack`**
  (optional) Atmos stack name
- **`component`**
  Atmos component name
- **`key`**
  The key to read from the store
- **`default-value`**
  (optional) The default value to return if the key is not found in the store
- **`yq-expression`**
  (optional) 
  [YQ](https://mikefarah.gitbook.io/yq)
   expression to retrieve individual values from the result

:::tip
You can use [Atmos Stack Manifest Templating](/templates) in the `!store` YAML function expressions.
Atmos processes the templates first, and then executes the `!store` function, allowing you to provide the parameters to
the function dynamically.
:::

:::note Type-Aware Merging
Atmos supports type-aware merging of YAML functions and concrete values, allowing them to coexist in the inheritance chain without type conflicts.
See the full explanation: [YAML Function Merging](/reference/yaml-function-merging)
:::

## Using YQ Expressions to retrieve individual values

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: !store <store_name> <stack> <component> <key> | query .private_subnet_ids[0]
```

- Read a key from a map

```yaml
username: !store <store_name> <stack> <component> <key> | query .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)

## Examples

**File:** `stack.yaml`

```yaml
components:
  terraform:
    my_lambda_component:
      vars:
        vpc_config:
          security_group_id: !store prod/ssm security-group/lambda id
          security_group_id2: !store prod/ssm {{ .stack }} security-group/lambda2 id
          security_group_id3: !store prod/ssm {{ .atmos_stack }} security-group/lambda3 id
        kms_key_arn: !store prod/ssm kms config | query .arn
```

## Specifying Atmos `stack`

If you call the `!store` function with three parameters, you need to specify the stack as the second argument.

There are multiple ways you can specify the Atmos stack parameter in the `!terraform.output` function.

### Hardcoded Stack Name

Use it if you want to get a value from the store for a component from a different (well-known and static) stack.
For example, you have a `tgw` component in a stack `plat-ue2-dev` that requires the `vpc_id` key from the `vpc` component from the stack `plat-ue2-prod`:

```yaml title="plat-ue2-dev"
  components:
    terraform:
      tgw:
        vars:
          vpc_id: !store prod/ssm plat-ue2-prod vpc vpc_id
```

### Reference the Current Stack Name

Use the `.stack` (or `.atmos_stack`) template identifier to specify the same stack as the current component is in
(for which the `!store` function is executed):

```yaml
  !store <store_name> {{ .stack }} <component> <key>
  !store <store_name> {{ .atmos_stack }} <component> <key>
```

For example, you have a `tgw` component that requires the `vpc_id` key from the store for the `vpc` component in the same stack:

```yaml
  components:
    terraform:
      tgw:
        vars:
          vpc_id: !store prod/ssm {{ .stack }} vpc vpc_id
```

:::note Using the `.stack` or `.atmos_stack` template identifiers to specify the stack is the same as calling the
`!store` function with two parameters without specifying the current stack, but without using `Go` templates. If you
need to get a value from the store from a component in the current stack, using the `!store` function with two
parameters is preferred because it has a simpler syntax and executes faster.
:::

### Use a Format Function

Use the `printf` template function to construct stack names using static strings and dynamic identifiers.
This is convenient when you want to override some identifiers in the stack name:

```yaml
  !store <store_name> {{ printf "%s-%s-%s" .vars.tenant .vars.environment .vars.stage }} <component> <key>

  !store <store_name> {{ printf "plat-%s-prod" .vars.environment }} <component> <key>

  !store <store_name> {{ printf "%s-%s-%s" .settings.context.tenant .settings.context.region .settings.context.account }} <component> <key>
```

- **\<component>**
  Placeholder for an actual component name (e.g. 
  `vpc`
  )
- **\<key>**
  Placeholder for an actual key (e.g. 
  `subnet_ids`
  )

For example, you have a `tgw` component deployed in the stack `plat-ue2-dev`. The `tgw` component requires the
`vpc_id` key from the store for the `vpc` component from the same environment (`ue2`) and same stage (`dev`), but from a different
tenant `net` (instead of `plat`):

```yaml title="plat-ue2-dev"
  components:
    terraform:
      tgw:
        vars:
          vpc_id: !store prod/ssm {{ printf "net-%s-%s" .vars.environment .vars.stage }} vpc vpc_id
```

:::tip Important
By using the `printf "%s-%s-%s"` function, you are constructing stack names using the stack context variables/identifiers.

For more information on Atmos stack names and how to define them, refer to `stacks.name_pattern` and `stacks.name_template`
sections in [`atmos.yaml` CLI config file](/cli/configuration/)
:::

## Considerations

- Using `!store` with secrets can expose sensitive data to standard output (stdout) in any commands that describe stacks or components.
- When using `!store` with [`atmos describe affected`](/cli/commands/describe/affected), Atmos requires access to all referenced stores.
  If you operate with limited permissions (e.g., scoped to `dev`) and reference production stacks, the command will fail.
- Be mindful of disaster recovery (DR) implications when using it across regions.
- Consider cold-start scenarios: if the dependent component has not yet been provisioned, the value in the store may not
  yet be available and the `!store` function call will fail unless you provide a default value with `| default`.
