Skip to main content

Environment Variables

System environment variables are managed through systemd’s environment.d directory.

Configuration Location

system/environment.d/
├── envvarsuser.conf       # User environment variables
├── rendering.conf         # Graphics rendering settings
└── wayland.conf           # Wayland-specific variables

User Environment Variables

envvarsuser.conf
# XDG Base Directory Specification
XDG_CONFIG_HOME=$HOME/.config
XDG_CACHE_HOME=$HOME/.cache
XDG_DATA_HOME=$HOME/.local/share
XDG_STATE_HOME=$HOME/.local/state

# ZSH configuration directory
ZDOTDIR=$XDG_CONFIG_HOME/zsh

# Default programs
EDITOR=nvim
VISUAL=nvim
TERMINAL=kitty
BROWSER=brave
PAGER="less -R"

# Less pager configuration
LESS='-R --mouse --incsearch'
LESSHISTFILE=$XDG_STATE_HOME/less/history

# Development tools home directories
CARGO_HOME=$XDG_DATA_HOME/cargo
RUSTUP_HOME=$XDG_DATA_HOME/rustup
GOPATH=$XDG_DATA_HOME/go
GOBIN=$XDG_DATA_HOME/go/bin
NPM_CONFIG_CACHE=$XDG_CACHE_HOME/npm
NPM_CONFIG_PREFIX=$XDG_DATA_HOME/npm
PYTHONUSERBASE=$XDG_DATA_HOME/python
PYTHONPYCACHEPREFIX=$XDG_CACHE_HOME/python
This configuration follows the XDG Base Directory Specification to keep your home directory clean.

XDG Base Directories

User-specific configuration files (~/.config)Applications store their config files here instead of cluttering $HOME
User-specific cache data (~/.cache)Temporary files that can be safely deleted
User-specific data files (~/.local/share)Application data, logs, and persistent storage
User-specific state data (~/.local/state)Logs, history files, and recently used files

Development Tools Configuration

All development tools are configured to use XDG directories:

Rust

CARGO_HOME=$XDG_DATA_HOME/cargo
RUSTUP_HOME=$XDG_DATA_HOME/rustup

Go

GOPATH=$XDG_DATA_HOME/go
GOBIN=$XDG_DATA_HOME/go/bin

Node.js

NPM_CONFIG_CACHE=$XDG_CACHE_HOME/npm
NPM_CONFIG_PREFIX=$XDG_DATA_HOME/npm

Python

PYTHONUSERBASE=$XDG_DATA_HOME/python
PYTHONPYCACHEPREFIX=$XDG_CACHE_HOME/python

PATH Configuration

The PATH is configured in home/zshenv to ensure all user binaries are accessible:
zshenv
# Load systemd environment
if [ -x /usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator ]; then
    set -a
    eval $(/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator 2>/dev/null)
    set +a
fi

# PATH configuration
typeset -U path
path=(
    "$HOME/.local/bin"
    "$CARGO_HOME/bin"
    "$GOBIN"
    "$NPM_CONFIG_PREFIX/bin"
    "$PYTHONUSERBASE/bin"
    "/usr/lib/ccache/bin"
    $path
)
path=($^path(N/))        # Keep only existing directories
export PATH

PATH Priority Order

1

~/.local/bin

User-installed binaries and scripts (highest priority)
2

Cargo bin

Rust binaries installed via cargo
3

Go bin

Go binaries installed via go install
4

NPM bin

Node.js global packages
5

Python bin

Python user packages (pip install —user)
6

ccache

Compiler cache for faster compilation
7

System PATH

System binaries (lowest priority)
The typeset -U path command ensures the PATH only contains unique entries, preventing duplicates.

Systemd User Environment

Loading Environment Variables

The zshenv file loads systemd environment variables at shell startup:
zshenv
if [ -x /usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator ]; then
    set -a
    eval $(/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator 2>/dev/null)
    set +a
fi
This ensures:
  • Environment variables from ~/.config/environment.d/*.conf are loaded
  • Variables are available to systemd user services
  • Consistent environment across all applications
Systemd user services (like hypridle.service) can access these environment variables.

Paru Configuration

Paru is the AUR helper used for package management.

Configuration File

paru.conf
[options]
PgpFetch              # Fetch PGP keys automatically
Devel                 # Check -git packages for updates
Provides              # Look for matching providers
BottomUp              # Show AUR packages first
SudoLoop              # Keep sudo timestamp alive
RemoveMake            # Remove makedeps after install
CleanAfter            # Clean build directory after install
CombinedUpgrade       # Upgrade both repos and AUR in one go
BatchInstall          # Install multiple packages in one batch
UpgradeMenu           # Show menu to select packages to upgrade
NewsOnUpgrade         # Show Arch news before upgrading
SaveChanges           # Save package changes
SkipReview            # Skip PKGBUILD review (use with caution)

DevelSuffixes = -git -cvs -svn -bzr -darcs -always -hg -fossil
SortBy = votes
SearchBy = name-desc
CompletionInterval = 7

[bin]
FileManager = yazi    # File manager for package files
Bat = bat             # Syntax highlighting for PKGBUILDs

Key Features

Automatic Updates

Checks -git packages for updates automatically

Clean Builds

Removes build dependencies and cleans up after install

Batch Operations

Install multiple packages efficiently

Arch News

Shows important news before system upgrades

Paru Usage Examples

# Update system (repo + AUR packages)
paru

# Search for packages
paru <package-name>

# Install package
paru -S <package-name>

# Remove package
paru -R <package-name>

# Clean cache
paru -Sc

# Show package info
paru -Si <package-name>
The SkipReview option is enabled for convenience but means you won’t review PKGBUILDs before installation. Consider disabling this if security is a concern.

Less Pager Configuration

Custom colors for the less pager (man pages):
zshenv
# Less pager colors
export LESS_TERMCAP_mb=$'\e[1;31m'      # Begin blinking
export LESS_TERMCAP_md=$'\e[1;36m'      # Begin bold (cyan)
export LESS_TERMCAP_me=$'\e[0m'         # End mode
export LESS_TERMCAP_se=$'\e[0m'         # End standout
export LESS_TERMCAP_so=$'\e[30;43m'     # Begin standout (yellow bg)
export LESS_TERMCAP_ue=$'\e[0m'         # End underline
export LESS_TERMCAP_us=$'\e[4;32m'      # Begin underline (green)
Result: Colorful, readable man pages instead of plain text.

Directory Structure

XDG-Compliant Layout

With this configuration, your home directory stays clean:
$HOME/
├── .config/              # XDG_CONFIG_HOME
│   ├── hypr/
│   ├── nvim/
│   ├── zsh/
│   ├── environment.d/
│   └── ...
├── .cache/               # XDG_CACHE_HOME
│   ├── npm/
│   ├── python/
│   └── zsh/
├── .local/
│   ├── bin/              # User binaries
│   ├── share/            # XDG_DATA_HOME
│   │   ├── cargo/
│   │   ├── go/
│   │   ├── npm/
│   │   └── python/
│   └── state/            # XDG_STATE_HOME
│       └── less/
└── .zshenv               # Only file in $HOME root
Following XDG standards makes backing up and restoring your configuration much easier.

Modifying System Configuration

1

Edit Environment Variables

nvim ~/dotfiles/system/environment.d/envvarsuser.conf
2

Reload Environment

# Reload shell
exec zsh

# Or log out and back in
3

Verify Changes

# Check specific variable
echo $VARIABLE_NAME

# Check PATH
echo $PATH | tr ':' '\n'
4

Commit Changes

cd ~/dotfiles
git add system/environment.d/
git commit -m "Update environment variables"

Troubleshooting

Ensure systemd user environment generator is executable:
ls -l /usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator
Reload shell: exec zsh
Check that ~/.zshenv is being loaded:
echo $ZDOTDIR
# Should output: /home/username/.config/zsh
Verify PATH in zshenv is correct
Update package databases:
paru -Sy
Check network connectivity and AUR availability

Next Steps

Shell Configuration

Customize your Zsh experience

Application Configs

Configure individual applications

Hyprland Setup

Window manager configuration

Overview

Configuration structure overview

Build docs developers (and LLMs) love