Warning
This repository is live and may change at any time. It is not guaranteed to work on all systems. It is recommended to use it as a reference and adapt it to your needs.
The configuration is written in a functional language called Nix. It looks like JSON with functions and allows us to manage various parts of our Operating System, including the installation of packages, the management of system settings, configuration files, and more. It supports host-based configurations for macOS and NixOS.
Note
A video on YouTube piqued my interest initially. If you're new to Nix, I recommend watching it first to get a basic understanding of what Nix is and how to configure it. It's your responsibility to learn more about Nix and adapt what's said in the video to your taste and requirements.
sh <(curl -L https://nixos.org/nix/install)This is ideally stored on a remote server/service that is going to be available at all times. GitHub is a good place as you've used it so far to store your dotfiles there anyway.
nix-shell -p git --run 'git clone [email protected]:simeonoff/tochki.git'This will launch a custom nix shell with git in it and git clone the configuration.
Before you can use the configuration, you need to enable flakes in your Nix installation:
mkdir -p ~/.config/nix
echo 'experimental-features = ["nix-command" "flakes"]' >> ~/.config/nix/nix.confnix run nix-darwin -- switch --flake ~/tochki#hostnamenix-shell -p home-manager --run home-manager switch --flake ~/tochki#user@hostnameVerify that the system configuration was installed correctly:
# Verify nix-darwin installation
darwin-rebuild --versionThis setup depends on the nix package manager being installed with the nix flakes feature enabled.
experimental-features = ["nix-command" "flakes"];After that, you can execute the following command while in the folder where your configuration will be stored:
nix flake init -t nix-darwinThis assumes that the host operating system is macOS.
After running the command, a new file flake.nix will be created. This file is essentially the entry point of the config that will be used when restoring the settings for packages, apps, and system settings to be applied.
To apply the config stored in this flake.nix file for the first time, all we have to do is the following (this command assumes you've initialized your config in ~/nix-config):
nix run nix-darwin -- switch --flake ~/nix-config#hostnameNote
For this configuration, I followed this approach for splitting my config into manageable parts. This means that home packages are managed independently of system packages installed using nix.
Here's a high-level overview (cheatsheet) of what needs to be run to update configs:
On macOS:
darwin-rebuild switch --flake ~/tochki#hostnameOn NixOS:
sudo nixos-rebuild switch --flake ~/tochki#hostnameOn both platforms:
home-manager switch --flake ~/tochki#username@hostnameTo learn more about flakes, visit the official wiki.
This is a simplified overview of the flake.nix file and the overall folder structure.
flake.nix- the entry point. Defining inputs for NixOS, nix-darwin, nix-homebrew, flake-parts, and Home Manager.flake.lock- Lock file ensuring reproducible builds.devshells- Nix shells for various development environments (node,python,go, etc.).hosts/- system configurations for each machine.home/- home manager configurations for each machine.files/- various files and scripts used across packages and modules.modules/- Reusable platform-specific modules:nixos/- NixOS-specific configuration modules.darwin/- macOS-specific configuration modules.home-manager/- Home Manager specific modules. Shared across systems.homebrew/- Homebrew related modules. Usually for macOS GUI applications.
overlays/- Custom Nix overlays for package modification or addition.
nixpkgs- Points tonixos-unstablechannel to access the latest packages.home-manager- Manages user-specific configurations. Follows latest stable input.nix-darwin- Enablesnix-darwinfor macOS specific configuration.nix-homebrew- Manages Homebrew installations on macOS vianix-darwin.flake-parts- Enables easy creation ofsystemspecific flakes.
-
Add a new user to the
usersattribute set:users = { # Existing users... newuser = { email = "[email protected]"; fullName = "Jon Snow"; sshKey = "YOUR PUBLIC SSH KEY"; name = "username"; }; };
-
Add the new host to the appropriate configuration set:
For
macOS:darwinConfigurations = { newhost = mkDarwinConfiguration "hostname" "username" };
For
NixOS:nixosConfigurations = { newhost = mkDarwinConfiguration "hostname" "username" };
-
Add the new home configuration:
homeConfigurations = { "newuser@newhost" = mkHomeConfiguration "arch" "newuser" "newhost"; };
-
Add a folder under
hosts/named after your host:mkdir -p hosts/newhost
-
Create
default.nixfor your new host. This will be the entry point for all system-related configurations:touch hosts/newhost/default.nix
-
Add some basic configuration in
default.nix:For
NixOShosts:{ hostname, nixosModules, ... }: { imports = [ ./hardware-configuration.nix "${nixosModules}/common" ]; networking.hostName = hostname; system.stateVersion = "24.11"; }
For
macOShosts:{ darwinModules, homebrewModules, ... }: { imports = [ "${darwinModules}/common" "${homebrewModules}/common" ]; system.stateVersion = 6; }
For NixOS hosts, generate the hardware-configuration.nix by running:
sudo nixos-generate-config --show-hardware-config > hosts/newhost/hardware-configuration.nix-
Create a couple of folders under
home/. The first should match the username (newuser), the second your hostname (newhost):mkdir -p home/newuser/newhost
-
Create
default.nixfor your new user under this host. This will be the entry point for all user home-related configurations:touch home/newuser/newhost/default.nix
-
Add some basic configuration in
default.nix:{ homeModules, ... }: { imports = [ "${homeModules}/common" ]; programs.home-manager.enable = true; home.stateVersion = "24.11"; }
From ~/tochki run:
git add .On macOS, run:
darwin-rebuild switch --flake ~/tochki#newhostOn NixOS, run:
sudo nixos-rebuild switch --flake ~/tochki#newhostImportant
On new systems, to ensure home-manager is available in your $PATH, run:
nix-shell -p home-manager --run home-manager switch --flake ~/tochki#newuser@newhostThis will execute home-manager in a nix shell and make it available to your host system.
After that you can simply run the following when changing your home configuration:
home-manager switch --flake ~/tochki#newuser@newhostThe following command updates all flakes and the respective packages:
nix flake updateNote
All homebrew packages will be automatically updated upon configuration updates.
If you encounter issues after updating or making changes to your configuration, you can roll back to a previous working state:
# Roll back to previous system generation
darwin-rebuild switch --flake ~/tochki#hostname --rollback
# Roll back home configuration
home-manager switch --flake ~/tochki#username@hostname --rollbackNote
Some modules have specific configurations that are not handled by home-manager. Neovim is a notable example. While home-manager still manages the package and extra-packages (only available in the Neovim environment) like LSPs, linters, formatters, etc., the Neovim configuration files are a part of the nix store. This allows us to manage plugins and editor configurations "live" without needing to rebuild the home-manager configuration after each change.
To change the configuration of Neovim, edit the files located directly under:
cd modules/home-manager/programs/neovim/config/nvim/To learn more about what packages are available, and what their respective options are:
- Visit search.nixos.org
- See home-manager options
Warning
Since nix package installations are read-only, we cannot simply do npm install -g package-name as it violates the Nix principles. You can read more about it here.
To work around this limitation, we create an ~/.npm-global folder where global packages will be stored. A global environment variable $NPM_CONFIG_PREFIX is set to this location.
This directory also needs to be added to the global $PATH.
In .zshrc add:
# Modifications for nodejs with nix
export PATH=${PATH}:${HOME}/.npm-global/binThis configuration automatically adds the path for Nushell, which is the default shell.
This configuration creates nix shells that can be used to quickly switch between Node.js versions. New nix shells can be added by creating a shell module and appending it to devshells/default.nix.
In the root of a project, create a .envrc file:
touch .envrcEdit the file and add the following line to it noting the development key in the attribute set of shells you've created.
The following line instructs direnv to use Node.js version 22 from our nix shells.
use flake ~/tochki#nodejs22To allow direnv to use the shell, run:
direnv allow .This configuration installs nh making it easy to reload and update the inputs in the configuration.
On macOS:
nh darwin switch On NixOS:
nh os switchOn macOS:
nh darwin switch --update
nh home switch --updateOn NixOS:
nh os switch --update
nh home switch --updatenh clean all --keep 5 # keep 5 generationsCommon issues you might encounter:
-
Flakes not enabled: If you get errors about flakes not being supported, ensure you've enabled experimental features as described in Step 3.
-
Permission denied errors: Ensure you have the correct permissions for the directories you're modifying.
-
Home-manager unavailable: Always use the nix-shell approach on a fresh system before using the regular home-manager command.