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: