Skip to content

Profile System

Aleem Isiaka edited this page Mar 31, 2026 · 4 revisions

Profile System

Manage different configurations for different machines and environments with Heimdal's profile system.

Table of Contents

Overview

Profiles let you define different configurations for different contexts:

  • Work laptop — Corporate tools, VPN configs, work-specific settings
  • Personal desktop — Personal apps, gaming tools, media configs
  • Server — Minimal setup, no GUI apps, server utilities

One dotfiles repository, multiple configurations.

Why Use Profiles?

Without profiles, you'd need separate dotfiles repositories per machine or manual cherry-picking of configurations. Profiles give you:

  • One repository for all machines
  • Shared base configuration with machine-specific additions
  • Easy switching between setups
  • Inheritance to reduce duplication

Basic Profile Setup

Single Profile

heimdal:
  version: "1"

profiles:
  default:
    packages:
      homebrew: [git, vim, tmux]
      apt: [git, vim, tmux]
    dotfiles:
      - .vimrc
      - .zshrc

Apply:

heimdal apply

Multiple Profiles

heimdal:
  version: "1"

profiles:
  work-laptop:
    packages:
      homebrew: [git, vim, tmux, kubectl, docker]
    dotfiles:
      - .vimrc
      - .zshrc

  personal-desktop:
    packages:
      apt: [git, vim, tmux, gimp]
    dotfiles:
      - .vimrc
      - .bashrc

  server:
    packages:
      apt: [git, vim, tmux, htop]
    dotfiles:
      - .vimrc
      - .bashrc

Switch to a profile and apply:

heimdal profile switch work-laptop
heimdal apply

Profile Inheritance

Profiles can extend other profiles with extends:. The merge rules are:

  • packages, dotfiles, templates, ignoreunioned (child entries are added on top of parent entries; per-manager package lists are merged)
  • hooksreplaced by the child (child hooks completely override parent hooks)

Base Profile Pattern

profiles:
  default:
    packages:
      common: [git, vim, tmux]
    dotfiles:
      - .vimrc
      - .zshrc
    ignore:
      - "*.swp"

  work-laptop:
    extends: default
    packages:
      homebrew: [kubectl, slack, zoom]
    hooks:
      post_apply:
        - "echo 'Work laptop configured'"

  personal-desktop:
    extends: default
    packages:
      homebrew_casks: [spotify, discord]

The effective work-laptop profile has git, vim, tmux (inherited from default), plus kubectl, slack, and zoom.

Viewing the Resolved Configuration

See what a profile looks like after inheritance is applied:

heimdal profile show work-laptop --resolved

Multi-Level Inheritance

You can chain inheritance up to any depth, though keeping it shallow (2–3 levels) is recommended for clarity:

profiles:
  base:
    packages:
      common: [git, vim]

  developer:
    extends: base
    packages:
      homebrew: [gh, docker]

  web-dev:
    extends: developer
    packages:
      homebrew: [node, yarn]

Profile Commands

Switch Profile

Switch the active profile. Run heimdal apply afterward to apply it:

heimdal profile switch <name>
heimdal apply

Show Current Profile

heimdal profile current

List All Profiles

heimdal profile list

Show Profile Configuration

# Show the raw profile definition
heimdal profile show <name>

# Show the profile after inheritance is resolved
heimdal profile show <name> --resolved

Compare Profiles

# Compare active profile with another
heimdal profile diff <name>

# Compare two specific profiles
heimdal profile diff <profile1> <profile2>

Create a Profile

heimdal profile create <name>

# Create extending an existing profile
heimdal profile create <name> --extends <base>

Clone a Profile

heimdal profile clone <source> <dest>

Conditional Configuration

Package lists per manager are automatically scoped to the current OS. If a profile defines both homebrew and apt packages, only the relevant manager's packages are installed.

For dotfiles, use when conditions to restrict individual entries:

profiles:
  default:
    dotfiles:
      - .vimrc
      - .zshrc

      # Only on macOS
      - source: .config/nvim
        target: ~/.config/nvim
        when:
          os: [macos]

      # Only on machines whose hostname matches this pattern
      - source: .ssh/config.work
        target: ~/.ssh/config
        when:
          hostname: "work-*"

See Dotfile Management — Conditional Dotfiles for the full when field reference.

Best Practices

1. Use a Base Profile for Common Config

profiles:
  default:
    packages:
      common: [git, vim, tmux]
    dotfiles:
      - .vimrc
      - .zshrc

  work:
    extends: default
    # Only work-specific config here

  personal:
    extends: default
    # Only personal-specific config here

2. Name Profiles Descriptively

Good names: work-mac, personal-linux, dev-server, home-desktop

Avoid: profile1, laptop, config

3. Keep Profiles Focused

Each profile should have a clear, single purpose. Avoid putting everything into one profile.

4. Preview Before Switching

heimdal profile show work-laptop --resolved
heimdal apply --dry-run

5. Document Your Profiles

Add YAML comments explaining each profile's purpose and the machines it's used on:

profiles:
  # Work laptop (MacBook Pro 2024)
  # Includes: Kubernetes, Docker, corporate tools
  work-mac:
    extends: default
    packages:
      homebrew: [kubectl, docker]

Troubleshooting

Profile Not Found

# List available profiles
heimdal profile list

# Check spelling in heimdal.yaml

Parent Profile Missing

Ensure the parent profile is defined before the child:

profiles:
  default:           # parent must exist
    packages:
      common: [git]

  work:
    extends: default  # references existing parent

Unexpected Packages After Extending

Remember that packages are unioned. If the parent has a homebrew: [git, vim] and the child has homebrew: [slack], the child's effective list is [git, vim, slack].

To see exactly what will be installed:

heimdal profile show <name> --resolved

Related Commands

heimdal profile list
heimdal profile show <name>
heimdal profile show <name> --resolved
heimdal profile switch <name>
heimdal profile current
heimdal profile create <name> --extends <base>
heimdal profile clone <source> <dest>
heimdal profile diff <name1> <name2>

Clone this wiki locally