Why I Love Using Nix for All My Projects
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 upruns. Databases and local services are ready before I type my first line of code. - Automated Config – The
shellHookwrites~/.docker/config.jsonautomatically, allowing pushes/pulls from AWS ECR without manualaws ecr get-login-passwordsteps. - Task Execution – Running
task dependencieschecks and verifies sub‑requirements (likenpm installorgo 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 theshellHookto interact with the outside world (your home directory for~/.dockerand 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.