NixOS + Home Manager for Multiple Users & Systems?

I installed and configured Nix along with Home Manager on my Mac (Ventura). Home Manager is configured as a flake, see below for details.

At this time, I’d like to install NixOS and reuse my existing home-manager configuration on a separate machine. To that end, I’d like to configure NixOS/Home Manager to adopt my configuration for all users.

For example, currently, I have to specify the user, e.g., "danke" = home-manager.lib.homeManagerConfiguration, username = "danke";, & homeDirectory = "/Users/danke";. Is there a way to have NixOS/Home Manager use whichever user is logged in? Thanks!

.
├── config.nix
├── flake.lock
├── flake.nix
└── modules
├── editors.nix
├── fonts.nix
├── home.nix
├── languages.nix
├── libraries.nix
├── sdks.nix
├── shells.nix
├── terminals.nix
├── utilities.nix
└── window_managers.nix

# Flake-based Home Manager: https://nix-community.github.io/home-manager/index.html#ch-nix-flakes
{
  description = "Home Manager Configuration";

  inputs = {
    home-manager = {
      url = "github:nix-community/home-manager/release-23.11";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    hyprland.url = "github:hyprwm/hyprland";
    # hyprland-plugins = {
    #   url = "github:hyprwm/hyprland-plugins";
    #   inputs.hyprland.follows = "hyprland";
    # };
    nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
  };

  outputs = inputs@{ home-manager, hyprland, nixpkgs, nixpkgs-unstable, ... }:
    let
      system = "aarch64-darwin";
      pkgs = nixpkgs.legacyPackages.${system};
      pkgs-unstable = nixpkgs-unstable.legacyPackages.${system};
    in
    {
      homeConfigurations = {
        "danke" = home-manager.lib.homeManagerConfiguration {
          inherit pkgs;
          extraSpecialArgs = { inherit inputs pkgs-unstable; };
          modules = [
            {
              home = {
                username = "danke";
                homeDirectory = "/Users/danke";
                stateVersion = "23.11";
              };
            }
            {
              nixpkgs.config.allowUnfree = true;
            }
            ./modules/home.nix
          ];
        };
      };
    };
}

I think it should be possible to use builtins.getEnv "USER" but then you would need to pass --impure option to every nix command invocation.

How about define an alias:
alias home-switch=‘home-manger switch --flake “~/.flake-dir#${USER}”’

I used to use a custom script for this that could do some more things (below for reference), but recently I’m using nh for local hosts and nixinate for remote hosts (servers without HM),with the following aliases:

nhh='nh home switch .'
nhs='nh os switch .'
nhus='nh os switch -u .'

which I then run from within my flake repo.

I’ve been wanting to checkout deploy-rs (after having all but discarded the others listed here as less fitting for my specific requirements), but haven’t gotten around to it yet.

The legacy script I used to use (as switch in my flake repo) is below (sorry it had grown longer than I remember, mostly because of the vscode plugins management, which I rarely use anymore since moving to nixvim).

Just for information, from it you could glean how both home-manager and nixos-rebuild switch are nothing more that CLI utils that do the same as nix build + running an activation script.

#! /usr/bin/env bash

THIS=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# NIXCMD="${NIXCMD:-nix --extra-experimental-features nix-command --extra-experimental-features flakes}"
NIXCMD="${NIXCMD:-nix}"
FLAKEPATH="${THIS}"/.
ACTION="${ACTION:-switch}"
BRANCH="${BRANCH:-main}"
REMOTEFLAKE="git+ssh://git@github.com/ppenguin/nixos-configs.git?ref=${BRANCH}"
# default is local host, overridden when --target <HOST> specified
TARGETHOST="$(hostname -s)"

# set +x
set -e

exiterr() {
	echo "$*"
	exit 1
}

nix_system() {
	echo "$(uname -m | sed -r 's/arm64/aarch64/g')-$(uname -s | awk '{print tolower($0)}')"
}

rebuild_home() {
	# home-manager ${ACTION} -b hmbak --flake "${FLAKEPATH}"
	case ${ACTION} in
		switch)
			echo "switching to new home config from ${FLAKEPATH}#homeConfigurations.${USER}@$(hostname -s).activationPackage"
			${NIXCMD} ${NIXOPTS} run "${FLAKEPATH}#homeConfigurations.${USER}@$(hostname -s).activationPackage"
			;;
		*)
			echo "building new home config from ${FLAKEPATH}#homeConfigurations.${USER}@$(hostname -s).activationPackage"
			${NIXCMD} ${NIXOPTS} build "${FLAKEPATH}#homeConfigurations.${USER}@$(hostname -s).activationPackage"
			;;
	esac
}

rebuild_target_home() {
	# home-manager ${ACTION} -b hmbak --flake "${FLAKEPATH}"
	case ${ACTION} in
		switch)
			echo "switching to new home config from ${FLAKEPATH}#homeConfigurations.${USER}@${TARGETHOST}.activationPackage"
			${NIXCMD} ${NIXOPTS} run "${FLAKEPATH}#homeConfigurations.${USER}@$(hostname -s).activationPackage"
			;;
		*)
			echo "building new home config from ${FLAKEPATH}#homeConfigurations.${USER}@$(hostname -s).activationPackage"
			${NIXCMD} ${NIXOPTS} build "${FLAKEPATH}#homeConfigurations.${USER}@$(hostname -s).activationPackage"
			;;
	esac
}

rebuild_system() {
	s="$(nix_system)"
	case ${s} in
		*darwin)
			echo "darwin-rebuild ${ACTION} --flake \"${FLAKEPATH}\""
			darwin-rebuild ${ACTION} --flake "${FLAKEPATH}"
			;;
		*linux)
			echo "nixos-rebuild ${ACTION} ${NIXOPTS} --use-remote-sudo --flake \"${FLAKEPATH}\""
			nixos-rebuild ${ACTION} ${NIXOPTS} --use-remote-sudo --flake "${FLAKEPATH}"  # $(hostname -s) is already implicit
			;;
		*)
			exiterr "Unsupported system ${s}"
			;;
	esac
}

# TODO: check system type (cross compile etc)
rebuild_target_system() {
	s="$(nix_system)"
	case ${s} in
		*linux)
			NIX_SSHOPTS=-t nixos-rebuild ${ACTION} ${NIXOPTS} --target-host "${TARGETHOST}" --use-remote-sudo --flake "${FLAKEPATH}#${TARGETHOST}"	# $(hostname -s) is already implicit
			;;
		*)
			exiterr "Unsupported system ${s}"
			;;
	esac
}

rebuild_boot() {
	if [[ $(nix_system) =~ linux ]]; then
		nixos-rebuild boot --use-remote-sudo --flake "${FLAKEPATH}"
		return 0
	fi
	exiterr "Rebuilding boot not supported for $(nix_system)"
}

function get_vsixpkg() {
	N="$1.$2"

	# Create a tempdir for the extension download.
	EXTTMP=$(mktemp -d -t vscode_exts_XXXXXXXX)

	URL="https://$1.gallery.vsassets.io/_apis/public/gallery/publisher/$1/extension/$2/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"

	# Quietly but delicately curl down the file, blowing up at the first sign of trouble.
	curl --silent --show-error --fail -X GET -o "$EXTTMP/$N.zip" "$URL"
	# Unpack the file we need to stdout then pull out the version
	VER=$(jq -r '.version' <(unzip -qc "$EXTTMP/$N.zip" "extension/package.json"))
	# Calculate the SHA
	SHA=$(nix-hash --flat --base32 --type sha256 "$EXTTMP/$N.zip")

	# Clean up.
	rm -Rf "$EXTTMP"
	# I don't like 'rm -Rf' lurking in my scripts but this seems appropriate.

	cat <<-EOF
{
	name = "$2";
	publisher = "$1";
	version = "$VER";
	sha256 = "$SHA";
}
EOF
}

update_vscode_ext() {
	VEXTCFG=${THIS}/home/${USER}/_programs/vscode
	if [ ! -d "${VEXTCFG}" ]; then
		echo "vscode definitions not found (${VEXTCFG} not found). Ignoring."
		return
	fi
	FMPEXTLIST="${VEXTCFG}/vscode-ext-marketplace.txt"
	FTARGET="${VEXTCFG}/vscode-ext-marketplace.inc.nix"

	{
		echo "["
		while read -r pn; do
			# shellcheck-ignore SC2046
			if ! grep -qE '^\s?#' <<<"$pn"; then
				get_vsixpkg $(tr '.' ' ' <<<"$pn")
			fi
		done < "${FMPEXTLIST}"
		echo "]"
	} | tee "${FTARGET}"
}

while [ $# -gt 0 ]; do
	case $1 in
		"--show-trace")
			NIXOPTS="${NIXOPTS} --show-trace"
			;;
		"--remote")
			export FLAKEPATH="${REMOTEFLAKE}"
			;;
		"--build")
			export ACTION="build"
			;;
		"--target")
			shift
			export TARGETHOST="${1}"
			;;
		"home")
			if [ "$TARGETHOST" = "$(hostname -s)" ]; then
				rebuild_home || exit 1
			else
				echo "rebuilding HM generation for other target system $TARGETHOST"
				rebuild_target_home || exit 1
			fi
			;;
		"system")
			if [ "$TARGETHOST" = "$(hostname -s)" ]; then
				rebuild_system || exit 1
			else
				echo "rebuilding for other target system $TARGETHOST"
				rebuild_target_system || exit 1
			fi
			;;
		"boot")
			rebuild_boot || exit 1
			;;
		"vscodext")
			update_vscode_ext || exit 1
			;;
		"all")
			rebuild_system || exit 1
			# update_vscode_ext
			rebuild_home || exit 1
			;;
		*)
			exiterr "expected 'home', 'system', 'all', 'vscodext'";;
	esac
	shift
done