OFFSET偏移
← All articlesOFFSET / FIELD NOTESNO. 038

A tutorial on user-level configuration with Home Manager

A complete introduction to installation, program modules, dotfiles, services, and activation.

English translation · Code and commands follow the Chinese original.

IN THESE READING PATHSHome Manager: managing user configuration ↗
About 7 min readStart reading

Example versions and usage boundaries#

This tutorial preserves historical Home Manager/NixOS 24.05 examples to explain the module structure. Before using them, choose compatible, supported inputs and check the corresponding options. home.stateVersion is a baseline for compatibility behavior; it normally retains the value used at initial configuration rather than changing with input upgrades. Building, activating, and validating application behavior are different levels of verification.

What it manages#

Home Manager is a tool in the Nix ecosystem dedicated to managing user-level configuration. It can manage:

  • User packages
  • Configuration files (dotfiles)
  • Environment variables
  • Services, such as systemd user services

Installing Home Manager#

Method 1: install as a NixOS module (recommended)

Integrate Home Manager into the NixOS system configuration:

# /etc/nixos/configuration.nix
{ config, pkgs, ... }:

{
  imports = [
    # 导入 Home Manager NixOS 模块
    <home-manager/nixos>
  ];

  # 配置用户及 Home Manager
  users.users.alice = {
    isNormalUser = true;
    home = "/home/alice";
    description = "Alice";
  };

  # 为用户 alice 配置 Home Manager
  home-manager.users.alice = { pkgs, ... }: {
    home.packages = with pkgs; [
      git
      vim
      htop
    ];
    
    # Git 配置
    programs.git = {
      enable = true;
      userName = "Alice";
      userEmail = "alice@example.com";
    };
    
    # Bash 配置
    programs.bash = {
      enable = true;
      shellAliases = {
        ll = "ls -la";
        ".." = "cd ..";
      };
    };
    
    # 状态版本(必须设置)
    home.stateVersion = "24.05";
  };
}

Rebuild the system:

sudo nixos-rebuild switch

Method 2: standalone installation (non-NixOS systems)

Install on any Linux/macOS system:

# 添加 nix-channel 通道
nix-channel --add https://github.com/nix-community/home-manager/archive/release-24.05.tar.gz home-manager
nix-channel --update

# 安装
nix-shell '<home-manager>' -A install

Create the configuration file:

# 生成初始配置
home-manager init

# 编辑
nano ~/.config/home-manager/home.nix

Method 3: install with Flakes (the modern approach)

# ~/.config/home-manager/flake.nix
{
  description = "Home Manager configuration";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
    home-manager = {
      url = "github:nix-community/home-manager/release-24.05";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, home-manager }: {
    homeConfigurations."alice" = home-manager.lib.homeManagerConfiguration {
      pkgs = nixpkgs.legacyPackages.x86_64-linux;
      modules = [ ./home.nix ];
    };
  };
}
# ~/.config/home-manager/home.nix
{ config, pkgs, ... }:

{
  home.username = "alice";
  home.homeDirectory = "/home/alice";

  home.packages = with pkgs; [
    firefox
    thunderbird
  ];

  home.stateVersion = "24.05";
  programs.home-manager.enable = true;
}

Activate the configuration:

home-manager switch --flake ~/.config/home-manager#alice

Basic Home Manager configuration#

Basic structure

{ config, pkgs, ... }:

{
  # 用户基本信息
  home.username = "alice";
  home.homeDirectory = "/home/alice";
  home.stateVersion = "24.05";  # 必需

  # 用户级别的软件包
  home.packages = with pkgs; [
    # 开发工具
    git
    vim
    tmux
    
    # 日常软件
    firefox
    vlc
    
    # 命令行工具
    htop
    ripgrep
    fd
    fzf
    bat
  ];

  # 启用 Home Manager
  programs.home-manager.enable = true;
}

Common commands explained

# 激活配置
home-manager switch

# 激活特定配置(Flakes)
home-manager switch --flake ~/my-config#user

# 构建配置,不激活,也不是运行时测试
home-manager build

# 回滚到上一版本
home-manager switch --rollback

# 查看历史版本
home-manager generations

# 激活指定历史代际(先从 generations 输出确认实际路径)
/path/from/home-manager-generations/activate

# 编辑配置文件
home-manager edit

# 检查构建出的激活脚本(不执行)
home-manager build
less result/activate

# 清理旧版本
home-manager expire-generations "-30 days"

Program configuration#

Complete Git configuration

programs.git = {
  enable = true;
  userName = "Alice";
  userEmail = "alice@example.com";
  
  # 额外配置
  extraConfig = {
    init.defaultBranch = "main";
    push.autoSetupRemote = true;
    pull.ff = "only";
    core = {
      editor = "vim";
      autocrlf = "input";
    };
  };
  
  # 忽略文件
  ignores = [
    "*.swp"
    "*.swo"
    ".DS_Store"
    "node_modules/"
  ];
  
  # Aliases
  aliases = {
    st = "status";
    co = "checkout";
    br = "branch";
    ci = "commit";
    lg = "log --oneline --graph --all";
  };
};

Vim/Neovim configuration

programs.vim = {
  enable = true;
  
  settings = {
    number = true;        # 显示行号
    relativenumber = true; # 相对行号
    tabstop = 2;          # Tab 宽度
    shiftwidth = 2;       # 缩进宽度
    expandtab = true;     # 空格代替 tab
    mouse = "a";          # 启用鼠标
  };
  
  extraConfig = ''
    " 自定义配置
    set hlsearch
    set incsearch
    set smartcase
    set ignorecase
    set clipboard=unnamedplus
    
    " 配色
    syntax on
    colorscheme desert
  '';
  
  # 插件(需要额外配置)
  plugins = with pkgs.vimPlugins; [
    vim-airline
    nerdtree
  ];
};

# 或使用 Neovim
programs.neovim = {
  enable = true;
  defaultEditor = true;
  
  plugins = with pkgs.vimPlugins; [
  nvim-treesitter
  telescope-nvim
  ];
  
  extraConfig = ''
    lua << EOF
    -- Lua 配置
    vim.wo.number = true
    vim.bo.expandtab = true
    EOF
  '';
};

Bash/Zsh/Fish configuration

# Bash
programs.bash = {
  enable = true;
  
  # 环境变量
  sessionVariables = {
    EDITOR = "vim";
    PAGER = "less";
    PATH = "$HOME/.local/bin:$PATH";
  };
  
  # 别名
  shellAliases = {
    ll = "ls -la";
    la = "ls -a";
    ".." = "cd ..";
    "..." = "cd ../..";
  };
  
  # 初始化脚本
  initExtra = ''
    # 自定义函数
    mkcd() {
      mkdir -p "$@" && cd "$@"
    }
    
    # 提示符
    PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
  '';
};

# Zsh(推荐)
programs.zsh = {
  enable = true;
  
  oh-my-zsh = {
    enable = true;
    theme = "robbyrussell";
    plugins = [ "git" "docker" "sudo" ];
  };
  
  zplug = {
    enable = true;
    plugins = [
      { name = "zsh-users/zsh-autosuggestions"; }
      { name = "zsh-users/zsh-syntax-highlighting"; }
    ];
  };
  
  # 环境变量
  envExtra = ''
    export PATH="$HOME/.cargo/bin:$PATH"
  '';
  
  shellAliases = {
    g = "git";
    ga = "git add";
    gc = "git commit";
    gp = "git push";
  };
};

# Fish
programs.fish = {
  enable = true;
  
  plugins = [
    { name = "fisher"; src = pkgs.fishPlugins.fisher.src; }
  ];
  
  shellAliases = {
    l = "ls -la";
    c = "clear";
  };
  
  shellInit = ''
    # Fish 配置
    set -x EDITOR vim
  '';
};

SSH configuration

programs.ssh = {
  enable = true;
  
  # 主机配置
  matchBlocks = {
    "github" = {
      host = "github.com";
      user = "git";
      identityFile = "~/.ssh/id_ed25519";
    };
    
    "myserver" = {
      host = "server.example.com";
      user = "admin";
      port = 2222;
      identityFile = "~/.ssh/id_server";
      extraOptions = {
        "ServerAliveInterval" = "60";
        "ServerAliveCountMax" = "3";
      };
    };
  };
  
  # 全局配置
  extraConfig = ''
    AddKeysToAgent yes
    IgnoreUnknown UseKeychain
    UseKeychain yes # 主要针对 macOS;Linux 通常应删除这一项
  '';
};

Tmux configuration

programs.tmux = {
  enable = true;
  
  # 快捷键前缀
  shortcut = "a";  # Ctrl+a
  
  # 基础配置
  baseIndex = 1;
  escapeTime = 0;
  historyLimit = 10000;
  
  # 插件
  plugins = with pkgs.tmuxPlugins; [
    sensible
    yank
    resurrect
    continuum
  ];
  
  extraConfig = ''
    # 鼠标支持
    set -g mouse on
    
    # 状态栏
    set -g status-bg black
    set -g status-fg white
    
    # 窗口标题
    set -g set-titles on
    set -g set-titles-string "#W"
    
    # 重新加载配置
    bind r source-file ~/.config/tmux/tmux.conf \; display "配置已重载!"
    
    # 窗口分割
    bind | split-window -h
    bind - split-window -v
    
    # 同步窗格
    bind y setw synchronize-panes
  '';
};

File management (Dotfiles)#

Home Manager can directly manage arbitrary configuration files:

# 创建配置文件
home.file = {
  # 简单的文本文件
  ".config/myapp/config.toml".text = ''
    [settings]
    theme = "dark"
    language = "zh"
  '';
  
  # 从本地文件复制
  ".config/alacritty/alacritty.yml".source = ./dotfiles/alacritty.yml;
  
  # 从 store 路径
  ".config/doom/config.el".source = pkgs.fetchFromGitHub {
    owner = "hlissner";
    repo = "doom-emacs";
    rev = "<fixed-commit>";
    hash = "sha256-<actual-source-hash>";
  } + "/templates/config.example.el";
  
  # 可执行脚本
  ".local/bin/my-script" = {
    source = ./scripts/my-script.sh;
    executable = true;
  };
  
  # 目录
  ".config/nvim/lua/custom".source = ./nvim-lua;
};

# 使用 xdg 配置(推荐)
xdg.configFile = {
  "i3/config".source = ./i3-config;
  "polybar/config.ini".text = ''
    [bar/main]
    width = 100%
    height = 30
  '';
};

xdg.dataFile = {
  # 数据文件
  "applications/myapp.desktop" = {
    text = ''
      [Desktop Entry]
      Name=MyApp
      Exec=myapp
      Type=Application
    '';
  };
};

Service management#

services = {
  # GPG 代理
  gpg-agent = {
    enable = true;
    enableSshSupport = true;
    pinentryPackage = pkgs.pinentry-curses;
  };
  
  # 密码管理器
  password-store = {
    enable = true;
    settings = {
      PASSWORD_STORE_DIR = "~/.password-store";
    };
  };
  
  # 剪贴板管理
  copyq = {
    enable = true;
  };
  
  # 键位修改
  keynav = {
    enable = true;
  };
};

Complete example#

{ config, pkgs, lib, ... }:

{
  home.username = "alice";
  home.homeDirectory = "/home/alice";
  home.stateVersion = "24.05";

  # === 软件包 ===
  home.packages = with pkgs; [
    # 开发
    git
    vim
    tmux
    vscode
    jetbrains.idea-community
    
    # 工具
    htop
    ripgrep
    fd
    fzf
    bat
    eza
    
    # 浏览器
    firefox
    chromium
    
    # 通讯
    thunderbird
    slack
    
    # 多媒体
    vlc
    obs-studio
  ];

  # === 程序配置 ===
  programs.home-manager.enable = true;
  
  programs.git = {
    enable = true;
    userName = "Alice";
    userEmail = "alice@example.com";
    extraConfig = {
      init.defaultBranch = "main";
      core.editor = "vim";
    };
  };
  
  programs.zsh = {
    enable = true;
    oh-my-zsh = {
      enable = true;
      theme = "robbyrussell";
      plugins = [ "git" "docker" ];  
    };
    shellAliases = {
      g = "git";
      l = "ls -la";
    };
  };
  
  programs.tmux = {
    enable = true;
    plugins = with pkgs.tmuxPlugins; [
      sensible yank
    ];
  };
  
  # === 环境变量 ===
  home.sessionVariables = {
    EDITOR = "vim";
    BROWSER = "firefox";
    TERMINAL = "alacritty";
  };
  
  # === 配置文件 ===
  home.file = {
    ".myconfig".text = "配置内容";
  };
  
  # === 服务 ===
  services.gpg-agent = {
    enable = true;
    enableSshSupport = true;
  };
}

How Home Manager works#

┌─────────────────────────────────────────┐
│         home.nix (你的配置)              │
└─────────────────┬───────────────────────┘
                  │ 解析为 Nix 表达式
                  ▼
┌─────────────────────────────────────────┐
│      Home Manager 生成激活脚本          │
│    - 创建符号链接到 ~/.config/           │
│    - 安装软件包到 ~/.nix-profile/        │
│    - 设置环境变量                        │
│    - 启动用户服务                        │
└─────────────────────────────────────────┘

During activation, Home Manager will:

  1. Create all configuration files as symbolic links
  2. Install the specified packages
  3. Set environment variables and aliases
  4. Start/stop the relevant services
  5. Maintain Home Manager generations. Conflicts with existing regular files normally prevent activation; backups require explicit configuration, such as the CLI option -b backup.

Checking interfaces in current versions#

The historical examples use Git's userName, userEmail, and extraConfig; current Home Manager provides a compatibility path for migrating to programs.git.settings. Shell, editor, and desktop options should also be checked against the pinned version. Home Manager generations restore the configuration and packages it manages; they do not restore application databases, secrets, or other mutable data.

References & further reading

  1. Home Manager manual ↗
  2. Home Manager command source ↗
  3. Home Manager file options source ↗
  4. Home Manager Git module source ↗

Adapted from technical notes. Examples use generic names.

Continue along a reading path

Home Manager: managing user configuration

  1. 01Home Manager integration and modular configuration
  2. 02Configuring a terminal environment with Home Manager
  3. 03Desktop and theme configuration with Home Manager
  4. 04Home Manager files and symbolic links
  5. 05Secrets management with Home Manager and NixOS
  6. 06A tutorial on user-level configuration with Home Manager
CONTINUE READING / NEXT ARTICLEFile and directory operations

Learn everyday file operations, from browsing and searching to links, archives, and disk-space queries.