Files
home-manager/docs/manual/usage/dotfiles.md
Austin Horstman 0ecfc72c7c docs: explain file collision handling
Document how Home Manager handles activation-time file collisions in the usage manual, including standalone backup flags, NixOS and nix-darwin module options, per-file force handling, recursive directory behavior, and out-of-store symlink sources.

Also clarify the home.file-style ignorelinks option description so recursive symlink behavior is easier to understand from the generated option docs.
2026-05-04 11:37:23 -05:00

5.3 KiB

Keeping your ~ safe from harm

To configure programs and services Home Manager must write various things to your home directory. To prevent overwriting any existing files when switching to a new generation, Home Manager will attempt to detect collisions between existing files and generated files. If any such collision is detected the activation will terminate before changing anything on your computer.

For example, suppose you have a wonderful, painstakingly created ~/.config/git/config and add

{
  # …

  programs.git = {
    enable = true;
    userName = "Jane Doe";
    userEmail = "jane.doe@example.org";
  };

  # …
}

to your configuration. Attempting to switch to the generation will then result in

$ home-manager switch
…
Activating checkLinkTargets
Existing file '/home/jdoe/.config/git/config' is in the way
Please move the above files and try again

This error is about a file that Home Manager wants to manage as a symbolic link in your home directory. It is separate from package profile collisions, which usually mention installPackages or a collision between .../bin/... path. For package collisions, see Why is there a collision error when switching generation?.

Resolving file collisions

The safest resolution is to inspect the existing path, move any settings you want Home Manager to manage into your configuration, and remove or move the unmanaged file before switching again.

For a standalone Home Manager installation, you can ask Home Manager to move unmanaged non-symlink paths out of the way during activation:

home-manager switch -b backup

With the command above, a colliding ~/.config/git/config is moved to ~/.config/git/config.backup before Home Manager links the managed file. If the backup path already exists then activation still aborts, so choose an extension whose backup path does not already exist.

Standalone activation can also run a custom command for each collision:

home-manager switch -B trash-put

The command receives the colliding path as an argument and must move or remove that path. If both -B and -b are set, the custom command takes precedence; the command may still use the HOME_MANAGER_BACKUP_EXT environment variable set by -b.

When Home Manager is used as a NixOS or nix-darwin module, configure the corresponding module options instead of passing standalone command line flags:

{
  home-manager.backupFileExtension = "backup";
}

or

{
  home-manager.backupCommand = "${pkgs.trash-cli}/bin/trash-put";
}

If both {option}home-manager.backupCommand and {option}home-manager.backupFileExtension are set, the command takes precedence. The extension is still exported to the command as HOME_MANAGER_BACKUP_EXT, so the command can use it when implementing its own backup naming. With {option}home-manager.backupFileExtension, Home Manager refuses to replace an existing backup path unless {option}home-manager.overwriteBackup is enabled:

{
  home-manager.backupFileExtension = "backup";
  home-manager.overwriteBackup = true;
}

::: {.warning} {option}home-manager.overwriteBackup allows activation to clobber existing backup files. Only enable it when those backup paths are disposable. :::

For individual files, many file options also support force = true:

{
  home.file.".config/example" = {
    source = ./example;
    force = true;
  };
}

This skips the collision check for the affected target and lets Home Manager replace the existing file or link. Use it sparingly; it can silently delete local changes.

Backup commands and backup extensions are intended for unmanaged non-symlink paths. If the colliding target is an unmanaged symbolic link, move it manually or use force = true after checking that the link target is safe to replace.

Advanced file behavior

The notes below apply to {option}home.file and to options based on the same file type, such as {option}xdg.configFile.

When a file source is a directory, {option}home.file.<name>.recursive changes how the directory is linked. With the default recursive = false, the target is one symbolic link to the source directory. With recursive = true, Home Manager creates a matching directory tree and links each leaf file into it.

Recursive directory linking has special overlap behavior. A direct duplicate target, such as two managed files both targeting foo, is an error. If a recursively linked directory provides foo/bar and another managed file also targets foo/bar, Home Manager keeps the recursive file by default and ignores the overlapping regular file.

The {option}home.file.<name>.onChange hook runs after the new files are linked. For recursive file entries, the hook is always run, so it should be written to be safe even when no leaf file actually changed.

Normally a path assigned to {option}home.file.<name>.source is copied or linked through the Nix store. To make Home Manager create a link to a live path outside the store, use config.lib.file.mkOutOfStoreSymlink:

{ config, ... }:

{
  home.file.".config/example".source =
    config.lib.file.mkOutOfStoreSymlink ./example;
}

This is useful when the target should follow changes to a mutable file or directory outside the store.