Why I Love Using Nix for All My Projects

Published: (January 10, 2026 at 04:18 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

Why I Love Using Nix for All My Projects

“It works on my machine” is a phrase that has haunted software development for decades. Whether it’s a teammate having a different version of Python, a CI server missing a specific C library, or your global Node.js version conflicting with a legacy project, environment drift is a silent productivity killer.

I resolved this by moving my entire development workflow to Nix Flakes. Nix guarantees that if a project works today, it will work exactly the same way six months from now, or on a completely different machine, without manual installation steps.

In modern software development, we don’t just write code; we manage a fleet of tools. Nix provides a declarative way to handle:

  • Isolation – No more polluting your global /usr/local/bin. Every tool stays within the project.
  • Reproducibility – Every dependency is pinned. If I use Python 3.12.1, everyone on the team uses 3.12.1.
  • Automation – Using the shellHook, we can automate the startup of services, credential helpers, and environment variables.

flake.nix

I use a flake.nix in every repository. This specific configuration handles a complex stack: Python (managed by uv), AWS (with ECR automation), Docker, and various security tools.

{
  description = "DevShell con Terraform, Docker, Python y ECR login";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs { inherit system; };

        pythonEnv = pkgs.python312.withPackages (ps: with ps; [
          pip
        ]);

        commonDeps = with pkgs; [
          pythonEnv
          uv
          git
          terraform
          python312
          awscli
          gcc
          stdenv.cc.cc.lib
          httpie
          go
          go-task
          docker
          amazon-ecr-credential-helper
          jq
          nodejs_20
          nodePackages.lerna
          google-chrome
          subfinder
          amass
          imagemagick
          yarn
        ];
      in {
        devShells.default = pkgs.mkShell {
          packages = commonDeps;

          shellHook = ''
            # 1. Python & uv Setup
            pyenv global system
            export pythonEnv=${pythonEnv}
            export PATH=$PATH:${pythonEnv}/bin

            # Ensure uv uses the Nix-provided Python interpreter
            export UV_PYTHON=${pythonEnv}/bin/python

            # 2. Service Orchestration
            docker compose up --build -d
            docker compose ps -a
            task dependencies

            # 3. AWS & Docker Credential Automation
            mkdir -p ~/.docker
            echo '{
              "credsStore": "ecr-login"
            }' > ~/.docker/config.json
            echo "Docker config set to use docker-credential-ecr-login"
          '';

          LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
            pkgs.stdenv.cc.cc.lib
          ];
        };
      });
}

The Declarative Environment

Inside commonDeps, I list everything from compilers (gcc) to specialized tools like amazon-ecr-credential-helper. When someone joins the project, they don’t need to install these manually. Nix fetches and links them into an isolated environment, keeping the host system clean and the project portable.

I use uv because of its incredible speed and seamless integration with existing Python environments. By setting export UV_PYTHON=${pythonEnv}/bin/python in the shellHook, I tell uv to use the exact Python binary managed by Nix, ensuring total consistency between the package manager and OS-level dependencies.

Why Nix Becomes a Project Manager

  • Automatic Infrastructure – As soon as I enter the shell, docker compose up runs. Databases and local services are ready before I type my first line of code.
  • Automated Config – The shellHook writes ~/.docker/config.json automatically, allowing pushes/pulls from AWS ECR without manual aws ecr get-login-password steps.
  • Task Execution – Running task dependencies checks and verifies sub‑requirements (like npm install or go mod download) as soon as the shell opens.

Activating the Setup

To activate the entire environment, I run:

nix --extra-experimental-features 'nix-command flakes' develop --impure --command zsh
  • --extra-experimental-features 'nix-command flakes' – Enables the modern Nix Flake commands required for this setup.
  • --impure – Allows the shellHook to interact with the outside world (your home directory for ~/.docker and the system Docker socket).
  • --command zsh – Drops me directly into my preferred shell with the full environment already loaded.

Conclusion

Nix has fundamentally transformed how I approach project setups. Instead of a long README.md containing dozens of manual installation steps that are prone to failure, I provide a single flake.nix that defines the entire universe for the project. It is faster, safer, and 100 % reproducible. If it works for me, it will work for you.

Back to Blog

Related posts

Read more »

Custom Cross Compiler with Nix

Article URL: https://www.hobson.space/posts/nixcross/ Comments URL: https://news.ycombinator.com/item?id=46372771 Points: 7 Comments: 0...