Skip to main content

Import Basics

Imports are how you keep your stack configurations DRY (Don't Repeat Yourself). Instead of copying the same settings into every stack file, you define them once and import them where needed.

Think of imports like #include in C or import in Python—you're bringing configuration from other files into the current one.

Your First Import

Let's say you have common tags that should apply to all resources in all environments:

stacks/globals.yaml

vars:
tags:
ManagedBy: Atmos
Team: Platform
CostCenter: Engineering

Now any stack can import these tags:

stacks/dev.yaml

import:
- globals

vars:
environment: development
region: us-east-1

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

The vpc component in the dev stack now has access to all the tags from globals.yaml, plus its own variables.

tip

The .yaml extension is optional in imports. - globals and - globals.yaml both work.

How Imports Work

When Atmos processes a stack file, it:

  1. Reads the imports list (top to bottom)
  2. Loads each imported file (recursively processing their imports too)
  3. Deep merges all configurations into one unified structure
  4. Applies the current file's configuration on top

The result is a single, merged configuration that behaves like one big YAML file.

Import Order Matters

Files are processed sequentially. Later imports override earlier ones.

stacks/aws-defaults.yaml

vars:
provider: aws
region: us-east-1

stacks/gcp-defaults.yaml

vars:
provider: gcp
region: us-central1

stacks/my-stack.yaml

import:
- aws-defaults
- gcp-defaults # This overrides AWS settings

# Result: provider=gcp, region=us-central1

Order changed:

stacks/my-stack.yaml

import:
- gcp-defaults
- aws-defaults # This overrides GCP settings

# Result: provider=aws, region=us-east-1

Multiple Imports

You can import as many files as you need:

stacks/prod.yaml

import:
- globals # Common tags
- aws-prod # AWS production settings
- networking # Network configuration
- security-policies # Security baselines

vars:
environment: production

All four files merge together, with later imports overriding earlier ones, and the current file overriding all imports.

Organizing Imports

A common pattern is to create a _defaults directory for shared configuration:

stacks/
├── _defaults/
│ ├── globals.yaml
│ ├── aws.yaml
│ └── tags.yaml
├── dev.yaml
├── staging.yaml
└── prod.yaml

stacks/_defaults/globals.yaml

vars:
tags:
ManagedBy: Atmos

stacks/dev.yaml

import:
- _defaults/globals
- _defaults/aws

vars:
environment: dev
info

The _defaults/ directory is just a convention. You can organize imports however makes sense for your project.

What Gets Merged?

Imports merge everything in the YAML structure:

  • Top-level vars
  • Component configurations
  • Backend settings
  • Metadata
  • Any custom keys you add

stacks/base.yaml

vars:
namespace: myapp

components:
terraform:
vpc:
vars:
enable_dns: true

stacks/dev.yaml

import:
- base

vars:
environment: dev

components:
terraform:
vpc:
vars:
cidr_block: "10.0.0.0/16"
# enable_dns: true is inherited

After merge:

vars:
namespace: myapp # From base
environment: dev # From dev

components:
terraform:
vpc:
vars:
enable_dns: true # From base
cidr_block: "10.0.0.0/16" # From dev

Common Import Patterns

1. Global + Regional + Environment

stacks/prod-us-east-1.yaml

import:
- _defaults/globals # Company-wide settings
- _defaults/aws-us-east-1 # Region-specific
- _defaults/prod # Environment-specific

2. Shared Component Defaults

stacks/_defaults/vpc-defaults.yaml

components:
terraform:
vpc:
vars:
enable_dns_hostnames: true
enable_dns_support: true

stacks/dev.yaml

import:
- _defaults/vpc-defaults

components:
terraform:
vpc:
vars:
cidr_block: "10.0.0.0/16" # Adds to defaults

3. Layered Configuration

import:
- _defaults/globals # Layer 1: Global
- _defaults/aws # Layer 2: Provider
- _defaults/networking # Layer 3: Domain
- _defaults/prod # Layer 4: Environment

Each layer adds or overrides settings from the previous layers.

Imports vs Inheritance

Confused about the difference?

Imports
Bring entire files into the current stack. All settings merge together. Use for sharing common configuration across stacks.
Inheritance
Make one component extend another component's configuration. Use for component variations (e.g., "vpc" extends "vpc-base").

We'll cover inheritance in the next section. For now, focus on imports for file-level reuse.

Key Takeaways

  • Imports bring configuration from other files into the current stack
  • Order matters - later imports override earlier ones
  • Deep merge combines all settings into one unified structure
  • Use for DRY configuration - define once, import everywhere
  • Organize in _defaults/ for clarity (optional convention)

What's Next

Imports get you far, but sometimes you need component-level reuse. That's where inheritance comes in: