Inheritance Basics
Inheritance lets you create variations of a component without duplicating configuration. Define a base component once, then extend it with different settings for different use cases.
Think of it like classes in object-oriented programming: you create a base "class" (component) and then extend it with specialized "subclasses" (component instances).
The Problem Inheritance Solves
Let's say you need three VPCs:
- Development VPC: Small CIDR, single NAT gateway
- Staging VPC: Medium CIDR, redundant NAT gateways
- Production VPC: Large CIDR, highly available NAT gateways, VPN
Without inheritance, you'd configure each one separately, copying most of the same settings:
stacks/dev.yaml
stacks/staging.yaml
That's a lot of duplication! Let's fix it with inheritance.
Your First Inherited Component
Step 1: Define a base component with common settings
stacks/_defaults/vpc-base.yaml
Step 2: Extend the base component
stacks/dev.yaml
Now vpc-dev automatically has enable_dns_hostnames, enable_dns_support, and enable_nat_gateway from the base component—no duplication needed!
How Inheritance Works
When you use inherits, Atmos:
- Loads the base component's configuration
- Merges it with the current component's configuration
- Current component values override base values
The child component gets everything from the parent, and can override any setting.
Base component
Child component
Abstract vs Real Components
Notice the type: abstract in the base component? This tells Atmos:
- Abstract Components
- Templates for inheritance. Cannot be deployed directly. Used as blueprints.
- Real Components
- Deployable infrastructure. Can be applied with
atmos terraform apply.
Abstract component (blueprint)
Real component (deployable)
Try to deploy the abstract component and Atmos will error. Only real components can be deployed.
Organizing Inherited Components
A common pattern is to keep base components in a _defaults/ directory or a catalog/:
stacks/
├── _defaults/
│ ├── vpc-base.yaml
│ ├── eks-base.yaml
│ └── rds-base.yaml
├── dev.yaml
├── staging.yaml
└── prod.yaml
stacks/_defaults/vpc-base.yaml
stacks/prod.yaml
Common Inheritance Patterns
1. Environment-Specific Sizing
Base component
Dev uses small instance
Prod uses large instance
2. Feature Flags
Base component
Production enables all features
3. Regional Defaults
Base for US regions
Base for EU regions (different CIDR)
Inheritance vs Imports
Still confused about when to use each?
- Imports
- Bring entire stack files together
- Share configuration across multiple stacks
- Example: Global tags, regional settings
- Bring entire stack files together
- Inheritance
- Create component variations
- Share configuration within component definitions
- Example: Base VPC → Dev VPC, Staging VPC, Prod VPC
- Create component variations
You'll often use both together:
import:
- _defaults/globals # Import stack-level settings
- _defaults/vpc-base # Import base component
components:
terraform:
vpc-prod:
metadata:
inherits:
- vpc-base # Inherit component settings
vars:
cidr_block: "10.0.0.0/16"
Key Takeaways
✅ Inheritance creates component variations without duplication ✅ Abstract components are blueprints for inheritance (not deployable) ✅ Real components can be deployed and can inherit from abstract ones ✅ Child components override parent values ✅ Use for component-level reuse (imports are for stack-level reuse)
What's Next
You've learned the basics of imports and inheritance. Now let's talk about organizing these files for real-world projects:
- Organize your Stacks - Catalogs, defaults, and naming
- Connect Components - Share data between components
- Advanced Inheritance - Multiple inheritance, mixins, and more