How can I set up flake based home-manager config for both intel and M1 macs?

I’m a returning newbie to Nix, trying to set up home-manager on two Macs as a brew replacement.

Since I’m starting from scratch this time, I’m using flakes with Nix 2.8.1 (macOS 12.3.1).

I’m getting things working on my personal Intel Mac mini at the moment and have this working config for my flake.nix:

{
  description = "My Home Manager flake";

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

  outputs = { home-manager, ... }:
    let
      system = "x86_64-darwin";
      username = "myusername";
    in {
      homeConfigurations.${username} = home-manager.lib.homeManagerConfiguration {
        # Specify the path to your home configuration here
        configuration = import ./home.nix;

        inherit system username;
        homeDirectory = "/Users/${username}";
        # Update the state version as needed.
        # See the changelog here:
        # https://nix-community.github.io/home-manager/release-notes.html#sec-release-21.05
        stateVersion = "21.11";

        # Optionally use extraSpecialArgs
        # to pass through arguments to home.nix
      };
    };

}

This works well. However, I am going to be getting a M1 MacBook Pro for work soon, so I will need to support both x86_64-darwin and aarch64-darwin systems. Note that my username will be the same on both and I expect that the contents of home.nix will be the same on both too (if everything I need is available for aarch64). How do I set up (and call) two different home-manager configs where only the system value is different?

Also, if it possible to configure things in such a way that on the M1 Mac, Nix will try first to build for aarch64 then fall back to the x86_64 version (which I can run with Rosetta) if the program cannot be built for aarch64 yet?

Thanks in advance for any help!

Unfortunately, homeConfigurations doesn’t really support multi-arch outputs like the other flake attrs do. It does support multi-host outputs, though, upon my request on the PR that added --flake: https://github.com/nix-community/home-manager/pull/1856#pullrequestreview-614215129

I will some day write docs to explain this, because I link that comment like once a month ;p

So, as a sketch you could do something like:

homeConfigurations."${username}@mac1" = home-manager.lib.homeManagerConfiguration {
  inherit username;
  configuration = import ./home.nix;
  system = "x86_64-darwin";
};
homeConfigurations."${username}@mac2" = home-manager.lib.homeManagerConfiguration {
  inherit username;
  configuration = import ./home.nix;
  system = "aarch64-darwin";
};

You could then make that follow DRY principles pretty easily by creating a basic attrset, and then putting system = xyz into it with //, like so:

let
  config = {
    # Stuff and things
  };
in {
  homeConfigurations."${username}@mac1" = home-manager.lib.homeManagerConfiguration (config // {system = "x86_64-darwin";});
  homeConfigurations."${username}@mac2" = home-manager.lib.homeManagerConfiguration (config // {system = "aarch64-darwin";});
}

Or well, any number of other ways you can achieve something similar :slight_smile:

Sadly I don’t have an answer to this question, I’ve seen others ask it, and I think the answer was “no”, but I’m not certain. You may need to do something along the lines of using both x86 and aarch64 nixpkgs for the aarch64 configuration, but nix may really dislike it if you do that. Some digging on this discourse may help, or someone who actually knows how macs work.

I think the box86 folks are also starting to look at answers to that question. Weird times we live in :wink:

@TLATER Thanks so much, that’s really helpful!

So to activate the mac2 configuration I would do this?

home-manager switch --flake .#myusername@mac2

Regarding my second question, I did find while digging around that you can set extra-platforms in nix.config, which looked promising, but it’s not clear from the docs whether it would do the smart thing it the situation I described. I’ll keep looking anyway.

Thanks again for your help!

That would work, but the point of upstream support is that you can just use:

home-manager switch --flake .#

Home manager will automatically fill in your username and hostname.

2 Likes

Thanks for clarifying - I’m still getting to grips with the syntax of flakes!