Profile Inheritance Guide
Profile inheritance lets you build configurations that extend and customize base profiles, reducing duplication and enabling context-specific setups.
Why Use Inheritance?
Instead of duplicating configuration across profiles:
# ❌ Without inheritance - lots of duplication
profiles:
home:
dotfiles:
- source: dotfiles/.bashrc
target: ~/.bashrc
- source: dotfiles/.gitconfig
target: ~/.gitconfig
install:
apt: [git, curl, vim]
work:
dotfiles:
- source: dotfiles/.bashrc
target: ~/.bashrc
- source: dotfiles/.gitconfig
target: ~/.gitconfig
- source: dotfiles/.work-config
target: ~/.work-config
install:
apt: [git, curl, vim, docker.io]
Use inheritance to share common configuration:
# ✅ With inheritance - clean and maintainable
profiles:
base:
dotfiles:
- source: dotfiles/.bashrc
target: ~/.bashrc
- source: dotfiles/.gitconfig
target: ~/.gitconfig
install:
apt: [git, curl, vim]
home:
extends: base
# Inherits everything from base
work:
extends: base
dotfiles:
- source: dotfiles/.work-config
target: ~/.work-config
install:
apt: [docker.io] # Added to base's packages
Basic Inheritance
Use the extends keyword to inherit from another profile:
profiles:
base:
dotfiles:
- source: dotfiles/.bashrc
target: ~/.bashrc
work:
extends: base
The work profile now includes everything from base.
Merging Behavior
Dotfiles
Dotfiles from both profiles are combined:
profiles:
base:
dotfiles:
- source: dotfiles/.bashrc
target: ~/.bashrc
work:
extends: base
dotfiles:
- source: dotfiles/.work-config
target: ~/.work-config
Result: work has both .bashrc and .work-config entries.
Install Blocks
Install blocks are merged per type:
profiles:
base:
install:
apt: [git, curl]
github:
- repo: BurntSushi/ripgrep
asset: ripgrep-{arch}.tar.gz
binary: rg
work:
extends: base
install:
apt: [docker.io] # Added to [git, curl]
Result: work installs git, curl, docker.io, and ripgrep.
Override Behavior
When the same target appears in both profiles, the child wins:
profiles:
base:
dotfiles:
- source: dotfiles/.gitconfig
target: ~/.gitconfig
work:
extends: base
dotfiles:
- source: dotfiles/.work-gitconfig
target: ~/.gitconfig # Overrides base
Result: work uses .work-gitconfig for ~/.gitconfig.
Multi-Level Inheritance
Inheritance can chain multiple levels:
profiles:
base:
install:
apt: [git]
developer:
extends: base
install:
apt: [curl, vim]
work:
extends: developer # Gets git, curl, vim
install:
apt: [docker.io]
Final result for work: git, curl, vim, docker.io
Common Patterns
Layered Configuration
profiles:
# Layer 1: Absolute minimum
minimal:
install:
apt: [git]
# Layer 2: Development basics
developer:
extends: minimal
dotfiles:
- source: dotfiles/.bashrc
target: ~/.bashrc
install:
apt: [curl, vim]
# Layer 3: Full workstation
workstation:
extends: developer
install:
apt: [build-essential]
github:
- repo: BurntSushi/ripgrep
asset: ripgrep-{arch}.tar.gz
binary: rg
Context-Specific Profiles
profiles:
base:
dotfiles:
- source: dotfiles/.bashrc
target: ~/.bashrc
home:
extends: base
install:
apt: [steam, discord]
work:
extends: base
install:
apt: [docker.io, kubectl]
Error Handling
Circular References
dottie detects and prevents circular inheritance:
profiles:
a:
extends: b
b:
extends: a # Error!
Error message:
Configuration validation failed:
• Circular profile inheritance detected: a → b → a
Missing Parent
profiles:
work:
extends: nonexistent
Error message:
Configuration validation failed:
• Profile 'work' extends 'nonexistent', but 'nonexistent' does not exist.
Best Practices
- Keep base profiles minimal - Only include truly common configuration
- Use meaningful names -
base,developer,worktell a clear story - Document inheritance - Add comments explaining the chain
- Test each profile - Validate all profiles, not just the ones you use
- Avoid deep chains - 2-3 levels is usually sufficient