Editing your config

Ternix gives you a starting point, not a fixed result. After you download the generated files, all further changes happen in your editor. The cycle is always the same. Edit, rebuild, check the result.

Add a package

System-wide on NixOS, add names to environment.systemPackages in configuration.nix.

environment.systemPackages = with pkgs; [
  git
  firefox
  ripgrep   # adding a tool is one line
];

For one user with Home-Manager, use home.packages in the home configuration.

home.packages = with pkgs; [ ripgrep bat ];

If you are unsure of a package's exact attribute name, search on the Ternix Packages page or on search.nixos.org/packages . The attribute name is what goes in the list, and it is not always the marketing name of the program. You can also search from the terminal. This needs the nix-command and flakes experimental features, which the generated config enables.

nix search nixpkgs ripgrep

Set an option

Options configure NixOS modules. Browse Options for what exists, then set the ones you want.

services.openssh.enable = true;
time.timeZone = "America/New_York";
networking.firewall.allowedTCPPorts = [ 80 443 ];

search.nixos.org/options lists every option with its type and default value, which tells you exactly what a given option expects. Pay attention to the type. Assigning a string to a boolean option is the most common mistake and produces a clear type error at build time.

Split into modules

As a config grows, move sections into their own files and pull them in with imports. Each imported file is a NixOS module with the same { config, pkgs, ... }: signature as the main file.

# configuration.nix
{
  imports = [
    ./hardware-configuration.nix
    ./desktop.nix
    ./services/web.nix
  ];
}

This keeps each file focused on one concern and makes modules reusable across machines. The NixOS manual covers the full module system, including options, config, and lib.mkIf for conditional configuration.

Common system tasks

A few edits come up for almost everyone. Add a user with sudo rights and an SSH key.

users.users.alice = {
  isNormalUser = true;
  extraGroups = [ "wheel" ];
  openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAA... user@host" ];
};

Open firewall ports (an allowedUDPPorts list exists for UDP).

networking.firewall.allowedTCPPorts = [ 80 443 ];

Enable the SSH daemon.

services.openssh.enable = true;

Set the hostname and timezone.

networking.hostName = "nixos-host";
time.timeZone = "America/New_York";

For anything else, the Finding packages and options page shows how to track down the right option.

Rebuild and read errors

On NixOS, rebuild the running system with this command.

sudo nixos-rebuild switch --flake .#nixos-host

Before committing a change to the live system, test it without making it the default boot entry.

sudo nixos-rebuild test --flake .#nixos-host

test applies the configuration to the running system immediately but does not update the boot entry. Rebooting returns to the last generation set as the boot default.

When a build fails, read the last error line first. It usually names the offending attribute and the type it expected. The output looks like this.

error: value is a string while a boolean was expected, at /etc/nixos/configuration.nix:12:5

Fix the attribute, rebuild, and repeat. Because the running system only changes when a build succeeds, a failed build leaves everything untouched. If a switch did go through but something broke, use this command to roll back to the previous generation.

sudo nixos-rebuild switch --rollback

You can also select any earlier generation from the boot menu at startup.

For Home-Manager standalone, run this rebuild command.

home-manager switch --flake .#user

user is the attribute name in the generated flake (homeConfigurations.user). Rename it in flake.nix if you prefer a different one, and match it here.

Advanced

nixos-rebuild build produces the system derivation without activating it, which is useful in CI or for inspecting the result before you switch.

nixos-rebuild build --flake .#nixos-host

nixos-rebuild dry-build shows what would be fetched or compiled without downloading anything.

nixos-rebuild dry-build --flake .#nixos-host

To test a full system in a virtual machine without touching your hardware, use these commands.

nixos-rebuild build-vm --flake .#nixos-host
./result/bin/run-nixos-host-vm

The runner script is named after networking.hostName in the config (here nixos-host), not the flake attribute.

When you need a package built differently, reach for pkgs.<name>.override to change arguments the package exposes, and overrideAttrs to patch the derivation directly. Both are documented in the Nixpkgs manual on overriding .

environment.systemPackages = [
  # change a compile-time flag the package exposes
  (pkgs.curl.override { http2Support = false; })
 
  # patch the derivation directly
  (pkgs.hello.overrideAttrs (old: {
    patches = (old.patches or []) ++ [ ./my-fix.patch ];
  }))
];

lib.mkIf gates a block of configuration on any boolean option, keeping the module self-contained. The block activates only when its condition holds. Here the firewall rule is added only when SSH is enabled.

{ config, lib, pkgs, ... }:
{
  config = lib.mkIf config.services.openssh.enable {
    networking.firewall.allowedTCPPorts = [ 22 ];
  };
}

References while editing

Continue to Flakes for how inputs and the lock file keep your config reproducible.