Skip to main content

Organizing Stacks

As your infrastructure grows, so does your stack configuration. A handful of YAML files quickly becomes dozens or hundreds. Good organization keeps everything manageable and makes it easy for your team to find what they need.

Let's look at proven patterns for organizing Atmos stacks at scale.

Start Simple​

If you're just getting started, keep it simple:

stacks/
├── dev.yaml
├── staging.yaml
└── prod.yaml

Each file is a complete environment. This works great for small projects with a few environments.

Add Shared Configuration​

As duplication creeps in, extract common settings:

stacks/
├── _defaults/
│ └── globals.yaml
├── dev.yaml
├── staging.yaml
└── prod.yaml
stacks/_defaults/globals.yaml
vars:
namespace: myapp
tags:
ManagedBy: Atmos
Team: Platform
stacks/dev.yaml
import:
- _defaults/globals

vars:
environment: dev

The _defaults/ directory is a convention (you can name it anything), but it's widely used and makes intent clear.

Organize by Hierarchy​

For larger projects with multiple regions and accounts, organize hierarchically:

stacks/
├── _defaults/
│ ├── globals.yaml
│ └── aws.yaml
├── orgs/
│ └── acme/
│ ├── _defaults.yaml
│ └── accounts/
│ ├── dev/
│ │ ├── _defaults.yaml
│ │ ├── us-east-1.yaml
│ │ └── us-west-2.yaml
│ └── prod/
│ ├── _defaults.yaml
│ ├── us-east-1.yaml
│ └── eu-west-1.yaml

This mirrors your cloud structure: Organization → Account → Region.

Each level can have _defaults.yaml files that apply to everything below them:

stacks/orgs/acme/_defaults.yaml
vars:
organization: acme
domain: acme.com
stacks/orgs/acme/accounts/prod/_defaults.yaml
import:
- orgs/acme/_defaults

vars:
environment: production
account_id: "123456789012"
stacks/orgs/acme/accounts/prod/us-east-1.yaml
import:
- orgs/acme/accounts/prod/_defaults

vars:
region: us-east-1

components:
terraform:
vpc:
vars:
cidr_block: "10.0.0.0/16"

Catalogs: Reusable Component Blueprints​

Catalogs are collections of pre-configured component blueprints. Think of them as a component library for your organization.

stacks/
├── catalog/
│ ├── vpc/
│ │ ├── vpc-base.yaml
│ │ ├── vpc-dmz.yaml
│ │ └── vpc-private.yaml
│ ├── eks/
│ │ ├── eks-base.yaml
│ │ └── eks-production.yaml
│ └── rds/
│ ├── rds-postgres.yaml
│ └── rds-mysql.yaml
└── orgs/
└── acme/
└── accounts/
└── prod/
└── us-east-1.yaml
stacks/catalog/vpc/vpc-base.yaml
components:
terraform:
vpc/base:
metadata:
component: vpc
type: abstract
vars:
enable_dns_hostnames: true
enable_dns_support: true
stacks/orgs/acme/accounts/prod/us-east-1.yaml
import:
- catalog/vpc/vpc-base

components:
terraform:
vpc-prod:
metadata:
inherits:
- vpc/base
vars:
cidr_block: "10.0.0.0/16"

Catalogs make it easy to browse available components and understand their default configurations.

Naming Conventions​

Good names make configuration self-documenting. Here are some proven patterns:

Stack Names​

Stack names are how you reference environments:

atmos terraform apply vpc -s prod-us-east-1
atmos terraform apply vpc -s dev-us-west-2

Common patterns:

  • {environment}-{region}: prod-us-east-1, dev-eu-west-1
  • {account}-{region}: production-us-east-1, sandbox-us-west-2
  • {org}-{account}-{region}: acme-prod-us-east-1

Configure your naming pattern in atmos.yaml:

atmos.yaml
stacks:
name_pattern: "{environment}-{region}"

File Names​

Match your file names to stack names for clarity:

stacks/
└── orgs/
└── acme/
└── accounts/
├── prod-us-east-1.yaml # Stack: prod-us-east-1
├── prod-us-west-2.yaml # Stack: prod-us-west-2
└── dev-us-east-1.yaml # Stack: dev-us-east-1

Component Instance Names​

Use descriptive names that indicate purpose:

components:
terraform:
vpc-production: # Good: indicates environment
vars: {}

vpc-dmz: # Good: indicates purpose
vars: {}

vpc-eks-cluster: # Good: indicates what uses it
vars: {}

vpc: # Less clear
vars: {}

Mixins: Cross-Cutting Configuration​

Mixins are small, focused configuration snippets that add specific functionality. Use them for cross-cutting concerns that don't fit a hierarchy.

stacks/
├── mixins/
│ ├── monitoring.yaml
│ ├── backup.yaml
│ └── compliance.yaml
stacks/mixins/monitoring.yaml
components:
terraform:
monitoring-mixin:
metadata:
type: abstract
vars:
enable_cloudwatch: true
enable_xray: true
log_retention_days: 30
stacks/prod-us-east-1.yaml
import:
- mixins/monitoring
- mixins/backup
- mixins/compliance

components:
terraform:
app:
metadata:
inherits:
- monitoring-mixin
vars:
# Monitoring settings inherited

Full Example Structure​

Here's a complete structure for a multi-account, multi-region setup:

stacks/
├── _defaults/
│ ├── globals.yaml # Company-wide settings
│ └── aws.yaml # AWS provider defaults
├── catalog/
│ ├── vpc/
│ │ ├── vpc-base.yaml
│ │ └── vpc-dmz.yaml
│ ├── eks/
│ │ └── eks-base.yaml
│ └── rds/
│ └── rds-postgres.yaml
├── mixins/
│ ├── monitoring.yaml
│ ├── backup.yaml
│ └── compliance.yaml
└── orgs/
└── acme/
├── _defaults.yaml
└── accounts/
├── dev/
│ ├── _defaults.yaml
│ ├── us-east-1.yaml
│ └── us-west-2.yaml
├── staging/
│ ├── _defaults.yaml
│ └── us-east-1.yaml
└── prod/
├── _defaults.yaml
├── us-east-1.yaml
├── us-west-2.yaml
└── eu-west-1.yaml

Each file is small and focused. Settings cascade down the hierarchy. Components reuse catalog blueprints.

Finding the Right Level​

Where should a setting go?

Globals (_defaults/globals.yaml)
Company-wide settings that apply everywhere: organization name, root domain, common tags
Org Defaults (orgs/acme/_defaults.yaml)
Organization-specific settings: billing alerts, compliance requirements, naming conventions
Account Defaults (accounts/prod/_defaults.yaml)
Account-level settings: account ID, environment, cost allocation tags
Region Files (us-east-1.yaml)
Region-specific components: VPCs, subnets, regional services
Component Config
Component-specific variables: CIDR blocks, instance sizes, feature flags

Rule of thumb: Put settings at the highest level where they apply, override lower as needed.

Key Takeaways​

✅ Start simple - Add structure as you need it ✅ Use _defaults/ for shared configuration - Widely recognized convention ✅ Organize hierarchically - Mirror your cloud structure (org/account/region) ✅ Create catalogs - Reusable component blueprints ✅ Use descriptive names - Make intent clear ✅ Mixins for cross-cutting concerns - Monitoring, backup, compliance

What's Next​

Your stacks are organized, but components need to talk to each other. Let's learn how to connect them: