# Inline Configuration

_Atmos Design Pattern_

**Inline Configuration** patterns define [components](/components) directly within [stack](/learn/stacks) manifests. This includes both fully inline configurations (no imports) and inline customizations of imported defaults.

If you're starting with Atmos, inline configurations are the easiest to understand until you need more advanced features.

## Fully Inline Configuration

The simplest approach: define all component configuration directly in each stack manifest without [importing](/stacks/imports) any base configurations.

### Use-cases

Use fully inline configuration when:

- You have a very simple organizational structure, e.g. one OU, one or a few accounts, one region

- You have a component that is provisioned only in one stack (e.g. only in the `dev` account). In this case, the component is configured inline in the
  stack manifest and is not used in other stacks

- For testing or development purposes

### Benefits

- Very simple stack and component configurations

- Define all components in just one place (in one stack manifest) so it's easier to see what and where everything is provisioned

### Example

Suppose you need a simple setup with only `dev`, `staging` and `prod` stages (accounts). Here's how you might organize the stacks and
inline-component configuration for the `vpc` and `vpc-flow-logs-bucket` components.

```console
   │   # Centralized stacks configuration (stack manifests)
   ├── stacks
   │   ├── dev.yaml
   │   ├── staging.yaml
   │   └── prod.yaml
   │
   │   # Centralized components configuration
   └── components
       └── terraform  # Terraform components (a.k.a Terraform "root" modules)
           ├── vpc
           ├── vpc-flow-logs-bucket
           ├── < other components >
```

Add the following minimal configuration to `atmos.yaml` [CLI config file](/cli/configuration) :

```yaml title="atmos.yaml"
components:
  terraform:
    base_path: "components/terraform"

stacks:
  base_path: "stacks"
  name_template: "{{.vars.stage}}"
```

Add the following component configurations to the `stacks/dev.yaml` stack manifest:

```yaml title="stacks/dev.yaml"
vars:
  stage: dev

components:
  terraform:
    vpc-flow-logs-bucket:
      metadata:
        # Point to the Terraform component
        component: vpc-flow-logs-bucket
      vars:
        enabled: true
        name: "vpc-flow-logs"
        traffic_type: "ALL"
        force_destroy: true
        lifecycle_rule_enabled: false

    vpc:
      metadata:
        # Point to the Terraform component
        component: vpc
      settings:
        # All validation steps must succeed to allow the component to be provisioned
        validation:
          validate-vpc-component-with-jsonschema:
            schema_type: jsonschema
            schema_path: "vpc/validate-vpc-component.json"
            description: Validate 'vpc' component variables using JSON Schema
          check-vpc-component-config-with-opa-policy:
            schema_type: opa
            schema_path: "vpc/validate-vpc-component.rego"
            # An array of filesystem paths (folders or individual files) to the additional modules for schema validation
            # Each path can be an absolute path or a path relative to `schemas.opa.base_path` defined in `atmos.yaml`
            # In this example, we have the additional Rego modules in `stacks/schemas/opa/catalog/constants`
            module_paths:
              - "catalog/constants"
            description: Check 'vpc' component configuration using OPA policy
      vars:
        enabled: true
        name: "common"
        max_subnet_count: 3
        map_public_ip_on_launch: true
        assign_generated_ipv6_cidr_block: false
        nat_gateway_enabled: true
        nat_instance_enabled: false
        vpc_flow_logs_enabled: true
        vpc_flow_logs_traffic_type: "ALL"
        vpc_flow_logs_log_destination_type: "s3"
        nat_eip_aws_shield_protection_enabled: false
        subnet_type_tag_key: "acme/subnet/type"
        ipv4_primary_cidr_block: 10.9.0.0/18
```

To provision the components, execute the following commands:

```shell
# `dev` stack
atmos terraform apply vpc-flow-logs-bucket -s dev
atmos terraform apply vpc -s dev
```

### Limitations

- If you have more than one stack (e.g. `dev`, `staging`, `prod`), then the component definitions would be repeated in the stack manifests,
  which makes them not reusable and the entire stack configuration not [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)

- Should be used only for specific use-cases (e.g. you have just one stack, or you are designing and testing the components)

---

## Inline Customization of Imported Defaults

A more powerful approach: define default component configurations in separate manifests, [import](/stacks/imports) them into top-level stacks, and customize inline as needed.

### Use-cases

Use inline customization when:

- You have components that are provisioned in multiple stacks (e.g. `dev`, `staging`, `prod` accounts) with different configurations for each stack

- You need to make the components' default/baseline configurations reusable across different stacks

- You want to keep the configurations [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)

### Benefits

- The defaults for the components are defined in just one place making the entire
  configuration [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)

- The defaults for the components are reusable across many stacks

- Simple stack and component configurations

### Example

Suppose you need a simple setup with only `dev`, `staging` and `prod` stages (accounts). Here's how you might organize the stacks and
component configurations for the `vpc` and `vpc-flow-logs-bucket` components, and then customize the components in the stacks.

```console
   │   # Centralized stacks configuration (stack manifests)
   ├── stacks
   │   ├── defaults  # component-specific defaults
   │   │   ├── vpc-flow-logs-bucket.yaml
   │   │   └── vpc.yaml
   │   ├── dev.yaml
   │   ├── staging.yaml
   │   └── prod.yaml
   │
   │   # Centralized components configuration
   └── components
       └── terraform  # Terraform components (a.k.a Terraform "root" modules)
           ├── vpc
           ├── vpc-flow-logs-bucket
           ├── < other components >
```

Add the following minimal configuration to `atmos.yaml` [CLI config file](/cli/configuration) :

```yaml title="atmos.yaml"
components:
  terraform:
    base_path: "components/terraform"

stacks:
  base_path: "stacks"
  name_template: "{{.vars.stage}}"
  excluded_paths:
    # Tell Atmos that the `defaults` folder and all sub-folders don't contain top-level stack manifests
    - "defaults/**/*"
```

Add the following default configuration to the `stacks/defaults/vpc-flow-logs-bucket.yaml` manifest:

```yaml title="stacks/defaults/vpc-flow-logs-bucket.yaml"
components:
  terraform:
    vpc-flow-logs-bucket:
      metadata:
        # Point to the Terraform component
        component: vpc-flow-logs-bucket
      vars:
        enabled: true
        name: "vpc-flow-logs"
        traffic_type: "ALL"
        force_destroy: true
        lifecycle_rule_enabled: false
```

Add the following default configuration to the `stacks/defaults/vpc.yaml` manifest:

```yaml title="stacks/defaults/vpc.yaml"
components:
  terraform:
    vpc:
      metadata:
        # Point to the Terraform component
        component: vpc
      settings:
        # All validation steps must succeed to allow the component to be provisioned
        validation:
          validate-vpc-component-with-jsonschema:
            schema_type: jsonschema
            schema_path: "vpc/validate-vpc-component.json"
            description: Validate 'vpc' component variables using JSON Schema
          check-vpc-component-config-with-opa-policy:
            schema_type: opa
            schema_path: "vpc/validate-vpc-component.rego"
            # An array of filesystem paths (folders or individual files) to the additional modules for schema validation
            # Each path can be an absolute path or a path relative to `schemas.opa.base_path` defined in `atmos.yaml`
            # In this example, we have the additional Rego modules in `stacks/schemas/opa/catalog/constants`
            module_paths:
              - "catalog/constants"
            description: Check 'vpc' component configuration using OPA policy
      vars:
        enabled: true
        name: "common"
        max_subnet_count: 3
        map_public_ip_on_launch: true
        assign_generated_ipv6_cidr_block: false
        nat_gateway_enabled: true
        nat_instance_enabled: false
        vpc_flow_logs_enabled: true
        vpc_flow_logs_traffic_type: "ALL"
        vpc_flow_logs_log_destination_type: "s3"
        nat_eip_aws_shield_protection_enabled: false
        subnet_type_tag_key: "acme/subnet/type"
        ipv4_primary_cidr_block: 10.9.0.0/18
```

Configure the `stacks/dev.yaml` top-level stack manifest:

```yaml title="stacks/dev.yaml"
vars:
  stage: dev

# Import the component default configurations
import:
  - defaults/vpc

components:
  terraform:
    # Customize the `vpc` component for the `dev` account
    # You can define variables or override the imported defaults
    vpc:
      vars:
        max_subnet_count: 2
        vpc_flow_logs_enabled: false
```

Configure the `stacks/staging.yaml` top-level stack manifest:

```yaml title="stacks/staging.yaml"
vars:
  stage: staging

# Import the component default configurations
import:
  - defaults/vpc-flow-logs-bucket
  - defaults/vpc

components:
  terraform:
    # Customize the `vpc` component for the `staging` account
    # You can define variables or override the imported defaults
    vpc:
      vars:
        map_public_ip_on_launch: false
        vpc_flow_logs_traffic_type: "REJECT"
```

Configure the `stacks/prod.yaml` top-level stack manifest:

```yaml title="stacks/prod.yaml"
vars:
  stage: prod

# Import the component default configurations
import:
  - defaults/vpc-flow-logs-bucket
  - defaults/vpc

components:
  terraform:
    # Customize the `vpc` component for the `prod` account
    # You can define variables or override the imported defaults
    vpc:
      vars:
        map_public_ip_on_launch: false
```

To provision the components, execute the following commands:

```shell
# `dev` stack
atmos terraform apply vpc -s dev

# `staging` stack
atmos terraform apply vpc-flow-logs-bucket -s staging
atmos terraform apply vpc -s staging

# `prod` stack
atmos terraform apply vpc-flow-logs-bucket -s prod
atmos terraform apply vpc -s prod
```

### Limitations

- The pattern is useful to customize components per account or region, but if you have more than one Organization, Organizational Unit (OU) or region,
  then the inline customizations would be repeated in the stack manifests, making the entire stack configuration
  not [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)

- Should be used only for specific use-cases, e.g. when you use just one region, Organization or Organizational Unit (OU)

---

## When to Use Each Approach

| Scenario | Recommended Approach |
|----------|---------------------|
| Learning Atmos or prototyping | Fully inline |
| Single environment deployment | Fully inline |
| Few environments, some shared config | Inline customization |
| Multi-region, multi-account | Consider [Configuration Catalog](/design-patterns/component-catalog) |

## Related Patterns

- [Configuration Catalog](/design-patterns/component-catalog)
- [Component Archetypes](/design-patterns/component-catalog/with-mixins)
- [Configuration Catalog Template](/design-patterns/component-catalog/template)
- [Component Inheritance](/design-patterns/inheritance-patterns/component-inheritance)
- [Organizational Structure Configuration](/design-patterns/stack-organization)
- [Partial Component Configuration](/design-patterns/configuration-composition/partial-component-configuration)
