NixOS
NixOS is a Linux distribution built entirely on top of the Nix package manager and the Nix language. This means your entire operating system, from the kernel to user-space applications and system services, is declared in a set of Nix expressions. This brings all the benefits of Nix (reproducibility, atomic upgrades, easy rollbacks) to your whole system.
NixOS Configuration (with Flakes)
With flakes, your NixOS configuration typically resides in a flake.nix
file that exports a nixosConfigurations
output.
Let's have a look at a basic flake.nix
for a NixOS machine.
# flake.nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
};
outputs =
{
self, # The flake itself
nixpkgs, # The nixpkgs input
...
}@inputs: # `self` and `nixpkgs` are available under `inputs`
let
inherit (self) outputs;
in
{
# Define NixOS configurations
nixosConfigurations = {
# Name for this specific system configuration
your-pc = nixpkgs.lib.nixosSystem {
# Arguments passed to all NixOS modules
specialArgs = {
inherit inputs outputs;
};
# List of all configuration files (modules)
modules = [ ./configuration.nix ];
};
};
};
}
The nixosSystem
function takes a list of modules
. Each module is a Nix expression that defines desired system state and settings. So the actual system configuration lives in configuration.nix
:
# configuration.nix
{ config, pkgs, ... }: # The arguments provided to a NixOS module
{
# Enable a display manager and desktop environment
services.displayManager.lightdm.enable = true;
services.desktopManager.gnome.enable = true; # Or kde, xfce, etc.
# List of packages to be installed globally
environment.systemPackages = with pkgs; [
firefox
neovim
git
];
# Configure networking
networking.hostName = "my-nixos-desktop";
# Users
users.users.Alice = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ]; # Add user to groups for sudo and network management
initialPassword = "changeme"; # Set a temporary password
};
# Set system-wide locale
i18n.defaultLocale = "en_US.UTF-8";
# Set the system time zone
time.timeZone = "America/New_York";
# ... many more options ...
}
Please note that the above configuration is not a complete working NixOS configuration. It just showcases how to you can define your system declaratively.
The config
argument is the evaluated final configuration of your system. You use it to refer to other parts of your configuration. For example, you might make one service depend on another's path:
It's primarily used for referencing options within the configuration.
The Module System
NixOS uses a powerful module system. A module is a Nix expression that declares:
- options
: What configurable parameters this module exposes.
- config
: How this module sets those parameters (and potentially other system parameters).
- imports
: Other modules to include.
When you build your NixOS configuration using nixos-rebuild switch --flake path/to/flake/directory#your-pc
, NixOS collects all the options and configurations from all activated modules, merges them, and then builds a new system closure in the Nix store.
Searching NixOS Options
There are thousands of options in NixOS. You can search them in the NixOS Options Search.
For example, search for services.desktopManager
to list all options regarding desktop managers.
Home Manager
While NixOS manages system-wide configurations, Home Manager applies the power of Nix to your user-specific configuration files and dotfiles. Instead of manually symlinking dotfiles or writing install scripts, you define your user environment declaratively in Nix. Home Manager applies Nix's declarative power to the user space, much like NixOS does for the system space.
Let's extend our flake.nix
:
# flake.nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
outputs =
{
self,
nixpkgs,
home-manager,
...
}@inputs:
let
inherit (self) outputs;
in
{
nixosConfigurations = {
your-pc = nixpkgs.lib.nixosSystem {
specialArgs = {
inherit inputs outputs;
};
modules = [ ./configuration.nix ];
};
};
homeConfigurations = {
your-user = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
extraSpecialArgs = {
inherit inputs outputs;
};
modules = [ ./home.nix ];
};
};
};
}
home.nix
might look like this:
# home.nix
{ config, pkgs, ... }:
{
# Define your user's home directory
home.username = "youruser";
home.homeDirectory = "/home/youruser";
# Install user-specific packages
home.packages = with pkgs; [
htop
cowsay
];
# Configure zsh
programs.zsh.enable = true;
programs.zsh.ohMyZsh.enable = true;
programs.zsh.ohMyZsh.plugins = [ "git" "history" ];
# Git configuration
programs.git = {
enable = true;
userName = "Your Name";
userEmail = "your.email@example.com";
};
# ... many more options for things like VS Code, Tmux, themes, fonts etc.
}
You could now build your Home Manager configuration with home-manager switch --flake path/to/flake/directory#your-user
.
Search for Home Manager options in the Home Manager Options Search.
What nix-core does
The nix-core
repository attempts to automate your NixOS and Home Manager experience. It exposes NixOS and Home Manager modules that sit on top of the already existing modules in NixOS and Home Manager respectively. Module options are added and opinionated defaults are set to get your configuration running with less configuration options needed to be set.
Create your NixOS and Home Manager configuration flake (we call that nix-config
) with nix-core as an input using a template provided in the repository. Adding NixOS and Home Manager configurations is automated through a shell script. You can choose between some configuration templates for server or client systems. The installation process is automated through a shell script as well. Also, an installation guide is provided. Rebuilding your NixOS and Home Manager configurations is wrapped in nix-core's rebuild script.
The Getting Started Guide will take you from nothing to a working NixOS configuration using nix-core.