DEV Community

Cover image for Nix first steps
Alexander Shagov
Alexander Shagov

Posted on • Edited on

Nix first steps

It might be overwhelming to dive into the Nix world, but this little glossary should help refine your understanding of the tools you might encounter when starting your journey.

UPD: I wrote one more short article to articulate why I prefer nix over non-nix setups in general: https://dev.to/alexander_shagov/why-use-nix-even-on-macos-786


Nix Package Manager – The core tool that allows declarative and reproducible package management.

NixOS – A Linux distribution built entirely on the Nix package manager. It's better to start with nix package manager alone before switching to NixOS completely.

Home Manager – Manages user packages, dotfiles, environment variables, shell configurations, and more. Allows for portable user environments across different machines.

Flakes – Provides a standardized structure for Nix projects, improving reproducibility and composability. It's worth noting that while Flakes are still technically experimental, they have been widely adopted by the Nix community due to their benefits. Many newer Nix configurations and projects are built using Flakes.


Old flow vs New flow

When you start searching for actual commands, you might encounter that some of them have different syntax (e.g., 'nix build' vs 'nix-build').

https://nixos-and-flakes.thiscute.world/nixos-with-flakes/introduction-to-flakes

Based on the article, there are two "flows" or approaches to using Nix: the old (or classic) flow and the new flow using flakes.

New Flow (Flakes and New CLI):

  • Introduces flake.nix and flake.lock files.

  • Uses new CLI commands that start with "nix" (e.g., nix develop, nix shell, nix build).

  • Replaces channels with explicit inputs in flake.nix.

  • Aims for improved reproducibility and composability.

Old Flow (Classic Nix):

  • Used commands like nix-channel, nix-env, nix-shell, and nix-build.

  • Relied on channels for package management.

  • Less standardized structure for Nix projects.

  • Could lead to less reproducible builds in some cases.

The new flow is essentially an evolution of Nix, addressing some limitations of the classic approach and borrowing ideas from other modern package managers (like npm, Cargo, etc.).

Assuming you're not using NixOS itself but, let's say, macOS, your flow of working with your development environment might look like this:

1) Use home-manager (preferably with flakes) to manage user-specific packages, tools, and configurations. This includes system-wide tools like Emacs, as well as dotfiles and environment settings.

2) For each project you're working on, create a flake.nix file to define the project-specific development environment and dependencies.


The aim of the article was to provide a good starting point and set up the mental model for further readings. Even though I didn't set a goal to share specific code snippets, here's the example of a home-manager (home.nix) file defining the global configuration on my MacOS. This configuration defines the global state of my system. Any project-related pieces live a in separate flake.nix files in their own namespaces. NOTE: I'm not using brew anyhow!


{ config, pkgs, ... }:

{
  home.username = "<username>";
  home.homeDirectory = "<homeDirectory>";

  home.stateVersion = "24.05";

  home.packages = with pkgs; [
    direnv
    ripgrep
    htop
    inetutils
    jq
    emacs29
    emacsPackages.vterm
  ];

  home.shellAliases = {
    # ============ git aliases =====================
    gs = "git status";
    gcm = "git checkout main && git pull";
    gc = "git checkout";
  };

  home.sessionVariables = {
    EDITOR = "emacs";
  };

  # ======== Zsh configuration ============

  programs.zsh = {
    enable = true; # Enable managing the Zsh configuration

    initExtra = ''

      # Private ENV vars configuration
      if [ -f ~/.bashrc_private ]; then
        . ~/.bashrc_private
      fi    

      # ========= Prompt with a branch ========
      function git_branch_name() {
           git rev-parse --abbrev-ref HEAD 2>/dev/null || echo '='
      }
      autoload -Uz colors && colors
      setopt prompt_subst
      prompt='%F{yellow}%~/%f [%F{green}$(git_branch_name)%f] > '

    '';
  };

  programs.direnv = {
    enable = true;
    # enableBashIntegration = true; # see note on other shells below
    nix-direnv.enable = true;
  };

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;
}
Enter fullscreen mode Exit fullscreen mode

Any time I need to add/remove system-wide package, or adjust, let's say, zsh configuration, it just boils down to editing the home.nix file and running the home-manager switch to apply the change (or home-manager build to see if a build compiles correctly).


Where to look for packages

Given you want to install htop. Just use the search.nixos.org and put the package name into your home.nix file. Run home-manager switch and you'll have your htop configured automatically (e.g. /Users/<username>/.nix-profile/bin/htop)

How to install a specific version of a package?

If you want to install a specific version of a package (not the latest one by default), you can search at nixhub.io. There, you'll see a specific Nixpkgs Reference you should use in your home.nix file to point to a specific version you're interested in.


Useful links for further reading


⭐ Comments and more useful articles for nix beginners appreciated!

Top comments (0)