Intro
NixOS really is the endgame of Linux in many respects, due to its reproducibility and stability. Because of flakes โ which allow you to pin your packages to a specific commit โ and Home Manager, which enables you to version control and reproduce your user configuration, the combination of these tools makes NixOS both rock solid like Debian and bleeding edge like Arch.
"In many respects, if Arch and Debian had a son, his name would be NixOS."
Let's jump into it.
Install from Minimal ISO
Reference: Official NixOS Installation Handbook
Load up Live ISO
Let's start by partitioning. I'm using the minimal ISO. Switch to root and set up the partition scheme:
sudo -i
lsblk
cfdisk /dev/vda
# GPT labels:
# 1G โ type: EFI
# 4G โ type: swap
# rest โ type: Linux Filesystem
Now format and label those partitions (the NixOS handbook recommends labels):
mkfs.ext4 -L nixos /dev/vda3
mkswap -L swap /dev/vda2
mkfs.fat -F 32 -n boot /dev/vda1
Mount them:
mount /dev/vda3 /mnt
mount --mkdir /dev/vda1 /mnt/boot
swapon /dev/vda2
[root@nixos:~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda 253:0 0 50G 0 disk
โโvda1 253:1 0 1G 0 part /mnt/boot
โโvda2 253:2 0 4G 0 part [SWAP]
โโvda3 253:3 0 45G 0 part /mnt
Initial NixOS Config
Generate the config and create the extra files:
nixos-generate-config --root /mnt
cd /mnt/etc/nixos/
touch flake.nix home.nix
flake.nix
The flake defines where packages come from so both configuration.nix and home.nix can inherit them consistently. A few things worth noting:
nixpkgsis shorthand forgithub:NixOS/nixpkgs/nixos-25.05inputs.nixpkgs.follows = "nixpkgs"prevents Home Manager from pulling its own version of nixpkgs- The
modulessection tells the flake to build the system usingconfiguration.nixand configure Home Manager for our user viahome.nix - Including Home Manager as a NixOS module means everything applies in one shot with
nixos-rebuild switchโ no separate bootstrapping
{
description = "NixOS from Scratch";
inputs = {
nixpkgs.url = "nixpkgs/nixos-25.05";
home-manager = {
url = "github:nix-community/home-manager/release-25.05";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, home-manager, ... }: {
nixosConfigurations.nixos-btw = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
home-manager.nixosModules.home-manager
{
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
users.tony = import ./home.nix;
backupFileExtension = "backup";
};
}
];
};
};
}
configuration.nix
Here's a clean configuration with the ly display manager, qtile window manager, and the essentials:
{ config, lib, pkgs, ... }:
{
imports = [ ./hardware-configuration.nix ];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
networking.hostName = "nixos";
networking.networkmanager.enable = true;
time.timeZone = "America/Los_Angeles";
services.displayManager.ly.enable = true;
services.xserver = {
enable = true;
autoRepeatDelay = 200;
autoRepeatInterval = 35;
windowManager.qtile.enable = true;
};
users.users.tony = {
isNormalUser = true;
extraGroups = [ "wheel" ];
packages = with pkgs; [ tree ];
};
programs.firefox.enable = true;
environment.systemPackages = with pkgs; [
vim wget alacritty git
];
fonts.packages = with pkgs; [
nerd-fonts.jetbrains-mono
];
nix.settings.experimental-features = [ "nix-command" "flakes" ];
system.stateVersion = "25.05";
}
home.nix
A minimal home.nix to start. We'll heavily modify this after the first boot:
{ config, pkgs, ... }:
{
home.username = "tony";
home.homeDirectory = "/home/tony";
programs.git.enable = true;
home.stateVersion = "25.05";
programs.bash = {
enable = true;
shellAliases = {
btw = "echo i use nixos, btw";
};
};
}
Install
nixos-install --flake /mnt/etc/nixos#nixos-btw
# Set your password before rebooting
nixos-enter --root /mnt -c 'passwd tony'
reboot
Post Install, First Boot
Open a terminal (Super+Enter in Qtile) and confirm Home Manager worked by running the alias we set:
btw
# โ i use nixos, btw
Create Dotfiles Directory
mkdir ~/nixos-dotfiles
sudo cp -R /etc/nixos/* ~/nixos-dotfiles/.
mkdir ~/nixos-dotfiles/config
git clone https://github.com/tonybanters/qtile ~/nixos-dotfiles/config/qtile
Modularize with mkOutOfStoreSymlink
Using mkOutOfStoreSymlink tells NixOS to create a live symlink from our dotfiles into ~/.config, so we can make live edits without running nixos-rebuild each time.
{ config, ... }
let
dotfiles = "${config.home.homeDirectory}/nixos-dotfiles/config";
create_symlink = path: config.lib.file.mkOutOfStoreSymlink path;
configs = {
qtile = "qtile";
nvim = "nvim";
};
in
{
xdg.configFile = builtins.mapAttrs (name: subpath: {
source = create_symlink "${dotfiles}/${subpath}";
recursive = true;
}) configs;
}
Turning Neovim Into Its Own .nix File
Move Neovim out of the main packages list into modules/neovim.nix. This keeps things modular and portable:
{ config, pkgs, lib, ...}
{
home.packages = with pkgs; [
ripgrep fd fzf
lua-language-server
nil nixpkgs-fmt
nodejs
];
programs.neovim = {
enable = true;
viAlias = true;
vimAlias = true;
};
}
Then import it in home.nix:
{pkgs, config, lib ...}:
{
imports = [ ./modules/neovim.nix ];
# ...
}
Final Thoughts
That's a complete NixOS setup from bare metal. You've got flakes pinning your packages, Home Manager handling your user config, live symlinks for your dotfiles, and Neovim in its own module. In the next installment we'll layer in unstable packages for tools where you want the bleeding edge.
If this was useful, check out the other tutorials on this site, or subscribe to the newsletter for new posts.