# Using External Stores

The `!store` YAML function reads data from external key-value stores like AWS SSM Parameter Store,
AWS Secrets Manager, Artifactory, Redis, and other backends. Use this when you need to share data outside Terraform state
or publish Terraform outputs to a store with an Atmos hook.

:::tip When to Use Stores vs Terraform State

- Use [`!terraform.state`](/stacks/sharing-state/terraform-state) for reading Terraform outputs (recommended)
- Use `!store` for reading from external systems like SSM, Artifactory, or other key-value stores
  :::

> **Key points**
>
> - Read from external key-value stores (SSM, Secrets Manager, Redis, Artifactory, etc.)
> - Configured in `atmos.yaml` with named store definitions
> - Supports default values for missing keys
> - Works with YQ expressions for complex data

## When to Use Stores

Use `!store` when you need to:

- Access configuration stored in SSM Parameter Store
- Share data that isn't managed by Terraform
- Integrate with external configuration management systems
- Store and retrieve data using Artifactory or Redis

For Terraform outputs, use [`!terraform.state`](/stacks/sharing-state/terraform-state) instead.

## Configuring Stores

Define stores in your `atmos.yaml`:

**File:** `atmos.yaml`

```yaml
stores:
  # AWS SSM Parameter Store
  ssm/prod:
    kind: aws/ssm
    options:
      region: us-east-1

  # AWS Secrets Manager
  asm/prod:
    kind: aws/asm
    options:
      region: us-east-1

  # Redis
  redis/cache:
    type: redis
    options:
      url: "redis://localhost:6379"

  # Artifactory
  artifacts:
    type: artifactory
    options:
      url: https://artifactory.example.com
      repo_name: my-repo
```

## Basic Usage

Read values from a configured store:

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

```yaml
components:
  terraform:
    app:
      vars:
        # Read from SSM Parameter Store
        api_key: !store ssm/prod app api_key

        # Read from Redis
        cached_config: !store redis/cache app config
```

## Syntax

```yaml
# Get key from store for component in current stack
!store <store_name> <component> <key>

# Get key from store for component in a different stack
!store <store_name> <stack> <component> <key>

# With default value
!store <store_name> <component> <key> | default <default-value>

# With YQ query
!store <store_name> <component> <key> | query <yq-expression>
```

## Cross-Stack References

Read from stores for components in different stacks:

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

```yaml
components:
  terraform:
    app:
      vars:
        # Read from a component in a different stack
        shared_config: !store ssm/prod shared-services config settings

        # Use template expressions for dynamic stack names
        vpc_id: !store ssm/prod {{ printf "%s-network" .vars.environment }} vpc vpc_id
```

## Default Values

Provide fallback values for missing keys:

```yaml
# String default
api_endpoint: !store ssm/prod api endpoint | default "https://api.example.com"

# The default is used if the key doesn't exist in the store
feature_flag: !store ssm/prod config feature_enabled | default false
```

## Working with Complex Data

Use YQ expressions to extract values from structured data:

```yaml
# Get a specific field from JSON stored in the store
db_host: !store ssm/prod database config | query .host

# Get first item from a list
primary_endpoint: !store ssm/prod cluster endpoints | query .[0]

# Navigate nested structures
api_key: !store ssm/prod app credentials | query .api.production.key
```

## Supported Store Backends

- **`aws/ssm` (legacy type: `aws-ssm-parameter-store`)**
  AWS Systems Manager Parameter Store.
- **`aws/asm` (legacy type: `aws-secrets-manager`)**
  AWS Secrets Manager.
- **`azure/keyvault` (legacy type: `azure-key-vault`)**
  Azure Key Vault for secrets management.
- **`gcp/secretmanager` (legacy types: `google-secret-manager`, `google/secretmanager`, `gsm`)**
  Google Cloud Secret Manager.
- **`redis`**
  Redis key-value store.
- **`artifactory`**
  JFrog Artifactory. Use a Generic repository type.

## Example: Multi-Store Configuration

**File:** `atmos.yaml`

```yaml
stores:
  # Production SSM store
  ssm/prod:
    kind: aws/ssm
    options:
      region: us-east-1
      # Optional: assume role for cross-account access
      read_role_arn: arn:aws:iam::123456789012:role/SSMReader

  # Development SSM store
  ssm/dev:
    kind: aws/ssm
    options:
      region: us-west-2

  # Artifactory for shared state
  artifacts:
    type: artifactory
    options:
      url: https://artifactory.example.com
      repo_name: infra-state
```

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

```yaml
components:
  terraform:
    app:
      vars:
        # Infrastructure config from SSM
        vpc_id: !store ssm/prod vpc vpc_id
        subnet_ids: !store ssm/prod subnets private_subnet_ids

        # Shared state from Artifactory
        network_config: !store artifacts network config
```

## Writing to Stores

Stores can be populated by Atmos hooks after Terraform applies. This keeps the
component outputs as the source of truth and avoids duplicating each output as a
provider-managed parameter resource:

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

```yaml
components:
  terraform:
    vpc:
      hooks:
        store-outputs:
          events:
            - after.terraform.apply
          kind: store
          name: ssm/prod
          outputs:
            vpc_id: .vpc_id
            private_subnet_ids: .private_subnet_ids
```

The hook writes each selected Terraform output under the store's
`prefix/stack/component/key` path. Other components can then consume the values
with same-stack or cross-stack `!store`, `!store.get`, or `atmos.Store` reads.

## Considerations

- **Secrets exposure**: `!store` reads in cleartext, so values may appear in stdout when describing stacks. For secrets, mark the store [`secret: true`](/cli/configuration/secrets) and use [`!secret`](/functions/yaml/secret), which masks values and gates access
- **Permissions**: You need read access to all referenced stores
- **Cold starts**: Returns error if the key doesn't exist (use `| default` to handle)
- **Latency**: External store calls add latency compared to `!terraform.state`
- **Consistency**: Ensure store values are updated when Terraform state changes

**Use !terraform.state for Terraform Outputs**

If you're reading Terraform outputs, `!terraform.state` is faster and doesn't require separate store configuration.
Learn More[Read more](/stacks/sharing-state/terraform-state)
