-
Notifications
You must be signed in to change notification settings - Fork 1
Profiles
Profiles allow you to maintain environment-specific configurations within a single dotfiles repository. With profiles, you can easily switch between different setups for work, home, servers, or any other environment without maintaining separate repositories or branches.
A profile in DotR consists of:
- Dependencies: Specific packages to deploy when using this profile
- Variables: Profile-specific variable values that override other sources
- Prompts: Interactive prompts for environment-specific credentials or values
- Target Overrides: Alternative deployment destinations for packages
Profiles are especially useful when:
- You have different configurations for work and personal machines
- You manage multiple servers with different requirements
- You want different setups for laptop vs desktop
- You need environment-specific credentials or settings
DotR automatically creates a default profile when you initialize a new repository with dotr init. This profile is used when:
- No
--profileflag is specified in commands - No
DOTR_PROFILEenvironment variable is set
The default profile behaves like any other profile, but with special characteristics:
- It's created automatically on
dotr init - It doesn't create target overrides when importing packages
- It's ideal for packages you want on all machines
Example:
# These both use the default profile
dotr deploy
dotr import ~/.bashrc
# Equivalent to:
dotr deploy --profile default
dotr import ~/.bashrc --profile defaultProfiles are defined in your config.toml. A default profile is automatically created by dotr init:
# The default profile is created automatically
[profiles.default]
dependencies = []
# Add custom profiles for different environments
[profiles.work]
dependencies = ["f_bashrc", "d_nvim", "f_gitconfig"]
[profiles.work.variables]
GIT_EMAIL = "work@company.com"
WORKSPACE = "~/Work"
[profiles.work.prompts]
VPN_PASSWORD = "Enter your work VPN password"
JIRA_TOKEN = "Enter your Jira API token"
[profiles.home]
dependencies = ["f_bashrc", "d_nvim", "d_gaming"]
[profiles.home.variables]
GIT_EMAIL = "personal@email.com"
WORKSPACE = "~/Projects"
[profiles.home.prompts]
GITHUB_TOKEN = "Enter your GitHub personal access token"# Deploy all packages in the work profile
dotr deploy --profile work
# Deploy all packages in the home profile
dotr deploy --profile home
# Deploy with the default profile (deploys packages in default profile's dependencies)
dotr deploy
# Set environment variable to override which profile is used by default
export DOTR_PROFILE=work
dotr deploy # Uses work profile instead of default# Import a file to the default profile
dotr import ~/.bashrc
# Import a file to a specific profile
dotr import ~/.ssh/config --profile work
# With DOTR_PROFILE environment variable
export DOTR_PROFILE=work
dotr import ~/.ssh/config # Uses work profile# Update packages for a specific profile
dotr update --profile work# See all variables with a profile applied
dotr print-vars --profile work
# With DOTR_PROFILE environment variable
export DOTR_PROFILE=work
dotr print-vars # Shows variables for work profileYou can set the DOTR_PROFILE environment variable to override which profile is used by default. Without this variable, DotR uses the default profile.
# Set in your shell configuration
export DOTR_PROFILE=work
# All commands now use the work profile instead of default
dotr deploy
dotr update
dotr import ~/.config/newfile
dotr print-vars
# Override with --profile flag
dotr deploy --profile home # Uses home instead of workThis is useful when:
- You primarily use one specific profile on a machine (not the default)
- You want to avoid typing
--profilerepeatedly - You're scripting deployments and want consistency
Shell Configuration Example:
# In ~/.bashrc or ~/.zshrc
if [[ "$HOSTNAME" == *"work"* ]]; then
export DOTR_PROFILE=work
elif [[ "$HOSTNAME" == *"home"* ]]; then
export DOTR_PROFILE=home
# else: uses default profile
fiDependencies specify which packages should be deployed when using a profile. This allows selective deployment based on the environment.
# Default profile - packages everyone gets
[profiles.default]
dependencies = ["f_bashrc", "f_gitconfig"]
# Work-specific packages
[profiles.work]
dependencies = ["f_bashrc", "f_gitconfig", "d_nvim", "f_ssh_config"]
# Home-specific packages
[profiles.home]
dependencies = ["f_bashrc", "f_gitconfig", "d_nvim", "d_gaming"]
# Minimal server setup
[profiles.server]
dependencies = ["f_bashrc", "f_gitconfig", "d_tmux"]Key Features:
- Only packages listed in dependencies are deployed
- Dependencies automatically include any package dependencies
- Unlisted packages won't deploy unless explicitly specified
- Use
skip = trueon packages to only deploy via profiles - When you run
dotr deploywithout--profile, thedefaultprofile is used
Profile variables override package and config variables but not user variables. They're perfect for environment-specific settings.
User Variables (.uservariables.toml) [Highest]
↓
Profile Variables (active profile)
↓
Package Variables
↓
Config Variables
↓
Environment Variables [Lowest]
[variables]
EDITOR = "vim"
THEME = "default"
[profiles.work]
dependencies = ["f_bashrc", "d_nvim"]
[profiles.work.variables]
EDITOR = "nvim"
THEME = "professional"
COMPANY = "Acme Corp"
[profiles.home]
dependencies = ["f_bashrc", "d_nvim"]
[profiles.home.variables]
EDITOR = "nvim"
THEME = "dracula"
PERSONAL_PROJECT = "~/hobby-code"In your templated configs:
# .bashrc
export EDITOR="{{ EDITOR }}"
export THEME="{{ THEME }}"
{% if COMPANY is defined %}
export COMPANY="{{ COMPANY }}"
{% endif %}Target overrides allow you to deploy the same package to different locations depending on the active profile.
[packages.ssh_config]
src = "dotfiles/ssh_config"
dest = "~/.ssh/config" # Default destination
[packages.ssh_config.targets]
work = "~/.ssh/config.work"
server = "/etc/ssh/ssh_config"When deploying:
# Deploys to ~/.ssh/config.work
dotr deploy --profile work -p ssh_config
# Deploys to /etc/ssh/ssh_config
dotr deploy --profile server -p ssh_config
# Deploys to ~/.ssh/config (default)
dotr deploy -p ssh_configThe skip flag marks packages to only deploy when explicitly requested or included in a profile's dependencies.
[packages.gaming]
src = "dotfiles/gaming"
dest = "~/.config/gaming"
skip = true # Only deploy via profile or explicit request
[packages.work_vpn]
src = "dotfiles/vpn"
dest = "~/.config/vpn"
skip = true
[profiles.home]
dependencies = ["gaming"] # gaming deploys with home profile
[profiles.work]
dependencies = ["work_vpn"] # work_vpn deploys with work profileProfile prompts allow you to interactively collect environment-specific values when deploying with a profile. This is perfect for credentials, API keys, or any sensitive data that varies between environments.
-
Define prompts in profile: Add a
[profiles.name.prompts]section -
Deploy with profile: Run
dotr deploy --profile name - Interactive input: DotR prompts for missing values
-
Automatic save: Values are saved to
.uservariables.toml - Reuse on next run: Saved values are reused - no re-prompting
[profiles.work]
dependencies = ["f_gitconfig", "f_ssh_config", "d_aws"]
[profiles.work.variables]
WORKSPACE = "~/Work"
[profiles.work.prompts]
WORK_EMAIL = "Enter your work email address"
VPN_PASSWORD = "Enter your work VPN password"
JIRA_TOKEN = "Enter your Jira API token"
AWS_PROFILE = "Enter your AWS profile name (e.g., work-prod)"
[profiles.home]
dependencies = ["f_gitconfig", "f_ssh_config"]
[profiles.home.variables]
WORKSPACE = "~/Projects"
[profiles.home.prompts]
PERSONAL_EMAIL = "Enter your personal email address"
GITHUB_TOKEN = "Enter your GitHub personal access token"First deployment:
$ dotr deploy --profile work
Enter your work email address
>>> john.doe@company.com
Enter your work VPN password
>>> ********
Enter your Jira API token
>>> abcd1234efgh5678
Enter your AWS profile name (e.g., work-prod)
>>> work-prod
[INFO] Saved prompts to .uservariables.toml
[INFO] Deploying profile 'work'...Subsequent deployments:
$ dotr deploy --profile work
[INFO] Using saved values from .uservariables.toml
[INFO] Deploying profile 'work'...Different Credentials per Environment:
[profiles.work.prompts]
GIT_EMAIL = "Enter your work email"
SSH_KEY_PATH = "Enter path to work SSH key"
JIRA_URL = "Enter Jira URL"
JIRA_TOKEN = "Enter Jira API token"
[profiles.home.prompts]
GIT_EMAIL = "Enter your personal email"
SSH_KEY_PATH = "Enter path to personal SSH key"API Keys and Tokens:
[profiles.production.prompts]
AWS_ACCESS_KEY = "Enter production AWS access key"
AWS_SECRET_KEY = "Enter production AWS secret key"
DATADOG_API_KEY = "Enter Datadog API key"
[profiles.staging.prompts]
AWS_ACCESS_KEY = "Enter staging AWS access key"
AWS_SECRET_KEY = "Enter staging AWS secret key"Machine-Specific Paths:
[profiles.laptop.prompts]
BACKUP_DIR = "Enter backup directory path"
SYNC_DIR = "Enter sync directory path"
[profiles.desktop.prompts]
BACKUP_DIR = "Enter backup directory path"
SYNC_DIR = "Enter sync directory path"When prompts are defined at multiple levels:
Profile Prompts (active profile) [Highest]
↓
Package Prompts (deployed packages)
↓
Config Prompts [Lowest]
Profile prompts override config-level prompts. This allows you to:
- Define common prompts at config level
- Override them with environment-specific prompts in profiles
Example:
# Config-level prompt (default)
[prompts]
EMAIL = "Enter your email address"
# Work profile overrides with work-specific prompt
[profiles.work.prompts]
EMAIL = "Enter your work email (@company.com)"
# Home profile overrides with personal prompt
[profiles.home.prompts]
EMAIL = "Enter your personal email"Prompted values are available in templates just like regular variables:
config.toml:
[profiles.work.prompts]
JIRA_TOKEN = "Enter your Jira API token"
JIRA_URL = "Enter your Jira URL"Template (dotfiles/f_jira_config):
export JIRA_URL="{{ JIRA_URL }}"
export JIRA_TOKEN="{{ JIRA_TOKEN }}"- Use for environment-specific secrets - Different API keys for work, home, staging, production
- Clear prompt messages - Include format examples in the prompt text
- Group related prompts - Keep all work credentials in work profile, home in home profile
- Document expected values - Add comments or README explaining what each prompt needs
- Combine with variables - Use variables for non-sensitive, prompts for sensitive data
- Test profile switching - Ensure prompts work correctly when switching between profiles
banner = true
[variables]
EDITOR = "vim"
SHELL = "bash"
# Default profile - base packages for all machines
[profiles.default]
dependencies = ["f_bashrc", "f_gitconfig"]
# Work profile
[profiles.work]
dependencies = ["f_bashrc", "f_gitconfig", "d_nvim", "f_ssh_config"]
[profiles.work.variables]
GIT_EMAIL = "john.doe@company.com"
GIT_NAME = "John Doe"
THEME = "gruvbox"
WORKSPACE = "~/Work"
SSH_KEY = "~/.ssh/id_ed25519_work"
[profiles.work.prompts]
VPN_PASSWORD = "Enter your work VPN password"
JIRA_TOKEN = "Enter your Jira API token"
CONFLUENCE_TOKEN = "Enter your Confluence API token"
# Home profile
[profiles.home]
dependencies = ["f_bashrc", "f_gitconfig", "d_nvim", "d_gaming"]
[profiles.home.variables]
GIT_EMAIL = "john@personal.com"
GIT_NAME = "John"
THEME = "dracula"
WORKSPACE = "~/Projects"
SSH_KEY = "~/.ssh/id_ed25519"
[profiles.home.prompts]
GITHUB_TOKEN = "Enter your GitHub personal access token"
PERSONAL_API_KEY = "Enter your personal API key"
# Packages
[packages.f_bashrc]
src = "dotfiles/f_bashrc"
dest = "~/.bashrc"
[packages.f_gitconfig]
src = "dotfiles/f_gitconfig"
dest = "~/.gitconfig"
[packages.d_nvim]
src = "dotfiles/d_nvim"
dest = "~/.config/nvim"
[packages.f_ssh_config]
src = "dotfiles/f_ssh_config"
dest = "~/.ssh/config"
[packages.f_ssh_config.targets]
work = "~/.ssh/config.work"
[packages.d_gaming]
src = "dotfiles/d_gaming"
dest = "~/.config/gaming"
skip = true # Only for home profile[profiles.webserver]
dependencies = ["f_bashrc", "d_nginx", "f_ssh_config"]
[profiles.webserver.variables]
SERVER_TYPE = "web"
LOG_DIR = "/var/log/webapp"
DATA_DIR = "/var/www"
[profiles.dbserver]
dependencies = ["f_bashrc", "d_postgres", "f_ssh_config"]
[profiles.dbserver.variables]
SERVER_TYPE = "database"
LOG_DIR = "/var/log/postgres"
DATA_DIR = "/var/lib/postgres"
[packages.d_nginx]
src = "dotfiles/nginx"
dest = "/etc/nginx"
skip = true
post_actions = [
"nginx -t && systemctl reload nginx || echo 'Nginx config invalid'"
]
[packages.d_postgres]
src = "dotfiles/postgres"
dest = "/etc/postgresql"
skip = true
post_actions = [
"systemctl reload postgresql"
][profiles.development]
dependencies = ["f_bashrc", "d_nvim", "d_docker", "d_kubernetes"]
[profiles.development.variables]
ENV = "dev"
DEBUG = "true"
API_URL = "http://localhost:3000"
[profiles.staging]
dependencies = ["f_bashrc", "d_docker", "d_kubernetes"]
[profiles.staging.variables]
ENV = "staging"
DEBUG = "false"
API_URL = "https://staging.example.com"
[profiles.production]
dependencies = ["f_bashrc", "d_kubernetes"]
[profiles.production.variables]
ENV = "production"
DEBUG = "false"
API_URL = "https://api.example.com"
[packages.d_kubernetes]
src = "dotfiles/kubernetes"
dest = "~/.kube"
[packages.d_kubernetes.targets]
development = "~/.kube/dev"
staging = "~/.kube/staging"
production = "~/.kube/prod"Actions can use profile variables for environment-specific behavior:
[packages.app_config]
src = "dotfiles/app"
dest = "~/.config/app"
pre_actions = [
"echo 'Deploying for {{ ENV }} environment'",
"mkdir -p {{ LOG_DIR }}"
]
post_actions = [
"{% if ENV == 'production' %}systemctl restart app{% else %}echo 'Dev mode, not restarting'{% endif %}"
][profiles.work]
[profiles.work.variables]
GIT_EMAIL = "work@company.com"
THEME = "professional"
[profiles.home]
[profiles.home.variables]
GIT_EMAIL = "personal@email.com"
THEME = "colorful"Template (dotfiles/f_gitconfig):
[user]
email = {{ GIT_EMAIL }}
[core]
# Work theme is minimal, home theme is colorful
pager = delta --theme="{{ THEME }}"Package variables still work within profiles:
[profiles.work]
dependencies = ["d_nvim"]
[profiles.work.variables]
COMPANY = "Acme Corp"
[packages.d_nvim.variables]
PLUGIN_MANAGER = "lazy.nvim"
LSP_ENABLED = trueBoth COMPANY (profile) and PLUGIN_MANAGER (package) are available in templates.
User variables override profile variables:
.uservariables.toml:
GIT_EMAIL = "john.doe+personal@company.com" # Overrides profileEven with --profile work, this email will be used instead.
-
Use descriptive profile names:
work,home,laptop,serverare clear and memorable -
Use the default profile for common packages: Put packages needed everywhere in the
defaultprofile - Keep profile dependencies minimal: Only include what's needed for that environment
- Use profile variables for credentials: Different emails, API keys, SSH keys per environment
- Leverage target overrides: Deploy configs to different paths per environment
-
Use skip flag wisely: Mark environment-specific packages with
skip = true - Document profiles: Add comments explaining what each profile is for
- Test profile switching: Verify templates render correctly with each profile
- Use profiles with actions: Different actions for different environments
- Combine with .uservariables.toml: Machine-specific overrides still work
- Keep base config minimal: Put environment-specific stuff in profiles
-
Use DOTR_PROFILE environment variable: Set it on machines where you want to use a specific profile instead of
default
# Clone your dotfiles
git clone https://github.com/user/dotfiles.git ~/dotfiles
cd ~/dotfiles
# Deploy work profile directly
dotr deploy --profile work
# Or set DOTR_PROFILE to always use work profile on this machine
echo 'export DOTR_PROFILE=work' >> ~/.bashrc
source ~/.bashrc
# Now deploy uses work profile automatically
dotr deploy # Uses work profile from DOTR_PROFILE# Deploy work configuration
dotr deploy --profile work
# Later, switch to home configuration
dotr deploy --profile home# On web server
dotr deploy --profile webserver
# On database server
dotr deploy --profile dbserver
# On monitoring server
dotr deploy --profile monitoring# Local development
dotr deploy --profile development
# Deploy to staging
dotr deploy --profile staging
# Deploy to production
dotr deploy --profile productionError: Profile 'myprofile' not defined
Solution: Verify the profile exists in config.toml:
[profiles.myprofile]
dependencies = [...]- Check the profile's
dependenciesarray includes the package - Verify package name matches exactly
- If using
skip = true, package must be in profile dependencies
- Check variable precedence: user > profile > package > config > environment
- Use
dotr print-vars --profile nameto see actual values - Verify profile name is correct when deploying
[packages.mypackage.targets]
myprofile = "~/alt/path" # Profile name must match exactlyEnsure you're using the correct profile name: dotr deploy --profile myprofile
Use templates to check which profile is active:
{% if ENV == "work" %}
export WORK_SPECIFIC_VAR="value"
{% elif ENV == "home" %}
export HOME_SPECIFIC_VAR="value"
{% endif %}Create a wrapper script or use environment variable:
Using DOTR_PROFILE:
# In ~/.bashrc or ~/.zshrc
if [[ "$HOSTNAME" == *"work"* ]]; then
export DOTR_PROFILE=work
elif [[ "$HOSTNAME" == *"home"* ]]; then
export DOTR_PROFILE=home
else
export DOTR_PROFILE=server
fi
# Now just run: dotr deployUsing a wrapper script:
#!/bin/bash
# deploy.sh
if [[ "$HOSTNAME" == *"work"* ]]; then
dotr deploy --profile work
elif [[ "$HOSTNAME" == *"home"* ]]; then
dotr deploy --profile home
else
dotr deploy --profile server
fiWhile profiles don't inherit directly, you can share packages across profiles. The default profile is a good place to put common packages:
# Common packages all machines get
[profiles.default]
dependencies = ["f_bashrc", "f_gitconfig"]
# Work adds work-specific packages
[profiles.work]
dependencies = ["f_bashrc", "f_gitconfig", "work_vpn"]
# Home adds home-specific packages
[profiles.home]
dependencies = ["f_bashrc", "f_gitconfig", "gaming"]Note that profiles don't automatically inherit from default - you need to explicitly list shared packages in each profile's dependencies.
- Configuration Guide - Learn about overall configuration
- Templating Guide - Use profile variables in templates
- Actions Guide - Profile-specific actions
- Variables Documentation - Variable precedence and usage