The “Works On My Machine” Problem
We’ve all been there:
Developer: “It works fine on my machine!” DevOps: “Well, it’s broken in production.”
The culprits are usually:
- Different package versions
- Missing dependencies
- Environment variables
- OS differences
- System libraries
Traditional solutions (Docker, virtual machines) help but don’t solve the root problem: deterministic, reproducible builds.
Enter Nix
Nix is a purely functional package manager. Every package build is:
- Deterministic: Same inputs always produce the same output
- Isolated: Packages don’t interfere with each other
- Reproducible: Build once, run anywhere
How Nix Works
The Nix Store
Everything lives in /nix/store/:
/nix/store/a7s9dk1...-python-3.11.5/
/nix/store/x9sk2f...-nodejs-18.17.0/
/nix/store/m2kd9s...-postgresql-15.3/
Each package has a unique hash based on its inputs: source code, dependencies, build scripts, compiler flags.
Change any input → different hash → different package.
Declarative Environments
Instead of apt install or brew install, you declare your environment:
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
go_1_21
postgresql_15
nodejs_18
bazel_6
];
shellHook = ''
echo "Development environment loaded!"
export DATABASE_URL="postgresql://localhost/myapp"
'';
}
Enter the environment:
nix-shell
# All tools are now available
go version # go1.21
node --version # v18.17.0
Real-World Use Case
Before Nix
Our team’s development setup:
# Install Homebrew (macOS) or apt (Linux)
# Install Go
# Install Node.js
# Install PostgreSQL
# Set environment variables in .bashrc/.zshrc
# Hope everyone has compatible versions
Problems:
- Takes 30-60 minutes to onboard new developers
- Version mismatches cause mysterious bugs
- “Did you update your Go version?”
- macOS and Linux developers have different setups
After Nix
git clone repo
cd repo
nix-shell
# Done. Identical environment for everyone.
Benefits:
- Onboarding takes 5 minutes
- Guaranteed version consistency
- Works identically on macOS and Linux
- No system pollution - everything in /nix/store
Beyond Development Environments
CI/CD
Same shell.nix works in CI:
# .github/workflows/test.yml
- name: Run tests
run: |
nix-shell --run "make test"
No more “works in CI but not locally” (or vice versa).
Production Builds
Build production artifacts with Nix:
{ pkgs ? import <nixpkgs> {} }:
pkgs.buildGoModule {
name = "myapp";
src = ./.;
vendorHash = "sha256-...";
}
The resulting binary is bit-for-bit reproducible. Build it today, build it next year with the same Nix configuration → identical output.
Docker Images
Generate minimal Docker images:
pkgs.dockerTools.buildLayeredImage {
name = "myapp";
contents = [ myapp ];
config = {
Cmd = [ "/bin/myapp" ];
};
}
No base image needed. Just your application and its dependencies.
The Learning Curve
I won’t lie - Nix has a steep learning curve:
Week 1: “What is this functional programming syntax?” Week 2: “Why are there so many different tools? (nix-shell, nix-build, flakes…)” Week 3: “I think I’m starting to get it…” Week 4: “This is actually amazing!”
Tips for Learning
- Start with nix-shell: Don’t try to learn everything at once
- Use nixpkgs search: https://search.nixos.org/packages
- Read others’ configs: GitHub is full of examples
- Join the community: NixOS Discourse, Reddit r/NixOS
- Be patient: The payoff is worth it
Common Pitfalls
1. Impure Builds
Nix builds are sandboxed - they can’t access the network or your home directory (by default).
Problem: Build scripts that download dependencies at build time Solution: Use fixed-output derivations or fetchurl
2. Binary Caches
Building from source is slow. Use Hydra (Nix’s binary cache):
substituters = [ "https://cache.nixos.org" ];
3. macOS Differences
Some packages work differently on macOS (especially with Apple Silicon).
Solution: Check nixpkgs issues, sometimes you need overrides
Our Team’s Nix Setup
# shell.nix
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
buildInputs = with pkgs; [
# Backend
go_1_21
golangci-lint
# Frontend
nodejs_18
yarn
# Infrastructure
kubectl
helm
terraform
# Database
postgresql_15
redis
# Tools
jq
yq-go
protobuf
bazel_6
];
shellHook = ''
export GOPATH=$PWD/.go
export PATH=$GOPATH/bin:$PATH
# Set up pre-commit hooks
if [ ! -f .git/hooks/pre-commit ]; then
ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit
fi
echo "🚀 Development environment ready!"
'';
}
Every developer gets:
- Exact same tool versions
- Properly configured PATH
- Environment variables set
- Pre-commit hooks installed
Nix Flakes
The future of Nix is Flakes - a new system for hermetic, reproducible Nix projects.
# flake.nix
{
description = "My development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.${system}.default = pkgs.mkShell {
buildInputs = with pkgs; [
go
nodejs
];
};
};
}
Flakes lock dependencies (like package-lock.json) for even better reproducibility.
Is Nix Right For You?
Use Nix if:
- You work on teams with different OSs
- “Works on my machine” bugs plague you
- You value reproducibility
- You’re willing to invest learning time
- You want declarative infrastructure
Skip Nix if:
- You’re a solo developer with simple needs
- You’re satisfied with Docker for development
- You need a solution RIGHT NOW (learning curve is real)
- Your team isn’t ready for the paradigm shift
The Bottom Line
Nix solved real problems for our team:
- ✅ Eliminated environment setup issues
- ✅ Made onboarding trivial
- ✅ Guaranteed dev/prod parity
- ✅ Enabled reproducible builds
But it required investment:
- ⏱️ Learning curve for the team
- 📚 Documentation isn’t always beginner-friendly
- 🐛 Occasional edge cases with packages
For us, the trade-off was absolutely worth it. Your mileage may vary.
Resources
- Nix Pills - Best learning resource
- NixOS Search - Find packages
- Nix by Example - Practical guides
- Zero to Nix - Modern tutorial
If you’re tired of environment issues and want true reproducibility, give Nix a try.
It might just change how you think about software development.
Have questions about Nix or want to share your setup? Let’s talk!