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:
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
Step 2: Extend the base component
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.
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.
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
Common Inheritance Patterns
1. Environment-Specific Sizing
2. Feature Flags
3. Regional Defaults
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