Skip to main content

Layered Stack Configuration

Atmos Design Pattern

The Layered Stack Configuration pattern organizes components into infrastructure layers based on their functionβ€”similar to how network architectures have distinct layers (network, transport, application). Each layer groups related components and can be managed independently.

Use-cases​

Use the Layered Stack Configuration pattern when:

  • You have many components that naturally group by function (networking, data, compute, etc.)

  • Different teams own different layers of infrastructure

  • You want to import only the layers needed for a specific environment

Benefits​

The Layered Stack Configuration pattern provides the following benefits:

  • Components are organized by their infrastructure function, making configs intuitive to navigate

  • Teams can own specific layers using tools like GitHub's CODEOWNERS

  • Stacks can import only the layers they need (e.g., a dev environment might skip the monitoring layer)

  • Changes to one layer don't affect other layers

Example​

The following example organizes infrastructure into three layers: network, data, and compute.

Directory Structure​

   β”œβ”€β”€ stacks
β”‚ β”œβ”€β”€ catalog # component defaults
β”‚ β”‚ β”œβ”€β”€ vpc
β”‚ β”‚ β”‚ └── defaults.yaml
β”‚ β”‚ β”œβ”€β”€ rds
β”‚ β”‚ β”‚ └── defaults.yaml
β”‚ β”‚ └── eks
β”‚ β”‚ └── defaults.yaml
β”‚ β”œβ”€β”€ layers # infrastructure layers
β”‚ β”‚ β”œβ”€β”€ network.yaml
β”‚ β”‚ β”œβ”€β”€ data.yaml
β”‚ β”‚ └── compute.yaml
β”‚ └── deploy
β”‚ β”œβ”€β”€ dev.yaml
β”‚ └── prod.yaml
β”‚
└── components
└── terraform
β”œβ”€β”€ vpc
β”œβ”€β”€ rds
└── eks

Configure atmos.yaml​

atmos.yaml

components:
terraform:
base_path: "components/terraform"

stacks:
base_path: "stacks"
included_paths:
- "deploy/**/*"
name_template: "{{.vars.stage}}"

Define the Layers​

Each layer imports the component defaults for that infrastructure function:

stacks/layers/network.yaml

import:
- catalog/vpc/defaults

# Network layer: VPC, subnets, security groups, etc.

stacks/layers/data.yaml

import:
- catalog/rds/defaults

# Data layer: databases, caches, message queues, etc.

stacks/layers/compute.yaml

import:
- catalog/eks/defaults

# Compute layer: EKS, ECS, Lambda, etc.

Import Layers into Stacks​

Stacks import the layers they need:

stacks/deploy/dev.yaml

import:
- layers/network
- layers/data
- layers/compute

vars:
stage: dev

# Dev-specific overrides
components:
terraform:
rds:
vars:
instance_class: db.t3.small

stacks/deploy/prod.yaml

import:
- layers/network
- layers/data
- layers/compute

vars:
stage: prod

# Prod-specific overrides
components:
terraform:
rds:
vars:
instance_class: db.r6g.xlarge
multi_az: true

Common Layer Examples​

Here are typical infrastructure layers you might define:

LayerComponentsPurpose
networkVPC, subnets, NAT, VPNFoundation networking
securityWAF, security groups, KMSSecurity controls
dataRDS, ElastiCache, S3Data storage
computeEKS, ECS, EC2Application runtime
observabilityCloudWatch, DatadogMonitoring and logging

Selective Layer Import​

Not every environment needs every layer. For example, a minimal dev environment might skip observability:

stacks/deploy/dev.yaml

import:
- layers/network
- layers/compute
# Skip observability in dev

vars:
stage: dev

While production includes everything:

stacks/deploy/prod.yaml

import:
- layers/network
- layers/security
- layers/data
- layers/compute
- layers/observability

vars:
stage: prod

Layer Dependencies​

Layers often have implicit dependencies. The compute layer depends on the network layer being provisioned first. Document or enforce this ordering in your deployment process:

# Deploy in layer order
atmos terraform apply vpc -s prod
atmos terraform apply rds -s prod
atmos terraform apply eks -s prod

References​