Skip to main content
User configuration in this flake is split across multiple locations to separate concerns between base user setup, system-level configuration, and home-manager profiles.

User configuration structure

Users are configured in three places:
  1. /modules/base/users/options.nix - Declares available users
  2. /modules/base/users/<user>.nix - SSH keys and base configuration
  3. /modules/nixos/users/<user>.nix - System-level settings (passwords, groups)
  4. /home/<user>/ - Home-manager configuration (optional)
  5. systems/<hostname>/users.nix - Per-system user assignments

Creating a new user

1

Add user to options.nix

Edit /modules/base/users/options.nix to include your new user in the default list:
modules/base/users/options.nix
{
  options.garden.system = {
    users = mkOption {
      type = listOf str;
      default = [ "isabel" "newuser" ]; # Add your user here
      description = '''
        A list of users that you wish to declare as your non-system users.
      ''';
    };
  };
}
If you don’t add any users to garden.system.users, you may end up with an unbootable system!
2

Create base user configuration

Create /modules/base/users/<user>.nix for SSH keys and basic settings:
modules/base/users/newuser.nix
{
  lib,
  config,
  ...
}:
let
  inherit (lib) elem mkIf;
in
{
  config = mkIf (elem "newuser" config.garden.system.users) {
    users.users.newuser = {
      openssh.authorizedKeys.keys = [
        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... newuser@machine"
      ];
    };
  };
}
Get your SSH public key with: cat ~/.ssh/id_ed25519.pub
3

Add system-level configuration

Create /modules/nixos/users/<user>.nix for password and system settings:
modules/nixos/users/newuser.nix
{
  lib,
  config,
  ...
}:
let
  inherit (lib) elem mkIf;
in
{
  config = mkIf (elem "newuser" config.garden.system.users) {
    users.users.newuser = {
      hashedPassword = "$y$j9T$vCF2V4znV5q3n6PxO5i6z/$...";
    };
  };
}
Generate a hashed password:
mkpasswd
# Enter your password when prompted
# Copy the resulting hash
4

Assign user to systems

In each system’s users.nix file, add the user:
systems/yoursystem/users.nix
{
  garden.system = {
    mainUser = "newuser";        # Optional: set as main user
    users = [ "isabel" "newuser" ]; # Add to users list
  };

  # Optional: Add home-manager configuration
  home-manager.users.newuser.garden = {
    profiles = {
      git.enable = true;
      shell.enable = true;
    };
  };
}
The mainUser is treated as the primary user on the system and may receive additional permissions or default configurations. If not specified, the first user in the users list becomes the main user.
5

Create home-manager configuration (optional)

For user-specific applications and settings, create /home/<user>/:
home/newuser/default.nix
{
  imports = [
    ./cli        # Command-line tools
    ./packages.nix  # User packages
  ];
}
See the Adding Packages guide for package configuration.

How user creation works

The mkuser.nix module automatically creates users declared in garden.system.users with sensible defaults:
modules/base/users/mkuser.nix
users.users = genAttrs config.garden.system.users (
  name:
  mergeAttrsList [
    {
      shell = "/run/current-system/sw/bin/${shell}";
    }

    (optionalAttrs (_class == "nixos") {
      home = "/home/${name}";
      uid = mkDefault 1000;
      isNormalUser = true;

      # Automatically added groups
      extraGroups = [
        "wheel"        # sudo access
        "nix"
        "networkmanager"
        "audio"
        "video"
        # ... and more
      ];
    })
  ]
);
This means you don’t need to manually configure:
  • Home directory location
  • Whether the user is a normal user
  • Basic group memberships
  • Shell configuration

Example user configurations

# modules/base/users/alice.nix
{
  lib,
  config,
  ...
}:
{
  config = lib.mkIf (lib.elem "alice" config.garden.system.users) {
    users.users.alice = {
      openssh.authorizedKeys.keys = [
        "ssh-ed25519 AAAAC3... alice@laptop"
      ];
    };
  };
}

# modules/nixos/users/alice.nix
{
  lib,
  config,
  ...
}:
{
  config = lib.mkIf (lib.elem "alice" config.garden.system.users) {
    users.users.alice = {
      hashedPassword = "$y$j9T$...";
    };
  };
}

User template structure

Here’s the recommended structure for a complete user setup:
modules/base/users/
└── yourname.nix          # SSH keys

modules/nixos/users/
└── yourname.nix          # Hashed password

home/yourname/
├── default.nix           # Main imports
├── packages.nix          # User packages
├── cli/                  # CLI tools config
│   ├── default.nix
│   ├── git.nix
│   └── shell/
├── gui/                  # GUI apps config
│   ├── default.nix
│   └── browser.nix
└── system/               # System integration
    ├── default.nix
    └── ssh.nix

systems/yoursystem/
└── users.nix             # User assignment

Managing user groups

Users automatically get added to common groups via mkuser.nix. To add additional groups:
systems/yoursystem/users.nix
{
  # Add user to extra groups
  users.users.yourname.extraGroups = [ "docker" "vboxusers" ];
}
Groups are only added if they exist on the system (using the ifTheyExist helper).

Next steps

Add packages

Install packages for your user

Secrets management

Set up user-level secrets

Adding systems

Create systems for your users

Troubleshooting

Fix common user issues

Build docs developers (and LLMs) love