# Nix + direnv Setup This project uses [Nix flakes](https://nixos.wiki/wiki/Flakes) to provide a reproducible dev environment that activates automatically when you `cd` into the project directory. No more "works on my machine" — every dev gets the same Elixir, Erlang, Rust, and PostgreSQL. ## How It Works 1. **Nix flakes** (`flake.nix`) declare every tool and library the project needs, pinned via `flake.lock`. 2. **direnv** watches for `.envrc` and loads/unloads the environment as you enter/leave the directory. 3. **nix-direnv** bridges the two, so `use flake` in `.envrc` triggers `nix develop`. The result: `cd` into the repo and you're ready to run `mix phx.server`. `cd` out and your shell is clean. No global installs, no version conflicts, no manual setup. ## File Layout | File | Purpose | |---|---| | `flake.nix` | Top-level flake: pins nixpkgs, Erlang/Elixir versions, defines dev shell | | `flake.lock` | Locked hashes for every dependency — reproducible across machines | | `nix/shell.nix` | Dev shell definition: packages, env vars, PostgreSQL service scripts, pre-commit hooks | | `shell.nix` | Flake-compat shim so `nix-shell` works without `--extra-experimental-features flakes` | | `.envrc` | Contains `use flake` (gitignored — create it yourself on each machine) | ## One-Time Setup ### 1. Install Nix (multi-user) ```bash sh <(curl -L https://nixos.org/nix/install) ``` Follow the prompts. The multi-user install (`--daemon`) is recommended on macOS. When it finishes, open a new terminal so the Nix daemon is running. Enable flakes. Add this to `~/.config/nix/nix.conf` (create the file if needed): ``` experimental-features = nix-command flakes ``` Verify: ```bash nix --version nix flake --help ``` ### 2. Install direnv ```bash brew install direnv ``` Add the direnv hook to your shell's rc file. Running `brew info direnv` will print the exact line — pick the one for your shell: **fish** (`~/.config/fish/config.fish`): ```fish direnv hook fish | source ``` **zsh** (`~/.zshrc`): ```zsh eval "$(direnv hook zsh)" ``` ### 3. Install nix-direnv ```bash brew install nix-direnv ``` Then configure direnv to load it. Create (or append to) `~/.config/direnv/direnvrc`: ```bash mkdir -p ~/.config/direnv cat > ~/.config/direnv/direnvrc << 'EOF' source "$(brew --prefix nix-direnv)/share/nix-direnv/direnvrc" EOF ``` If you installed nix-direnv via `nix profile` instead of Homebrew, the source line is: ``` source $HOME/.nix-profile/share/nix-direnv/direnvrc ``` ### 4. Create `.envrc` ```bash echo 'use flake' > .envrc ``` This is gitignored — each dev creates their own. You can add personal overrides (e.g., extra env vars) here. ### 5. Restart your shell Open a new terminal tab or `exec $SHELL` so the direnv hook takes effect. ### 6. First time entering the project directory ```bash cd ~/dev/prop direnv allow # one-time approval — thereafter it loads automatically ``` The first build may take several minutes while Nix downloads and compiles packages (Erlang, Elixir, Rust, PostgreSQL, etc.). Subsequent entries are instant — direnv caches the shell. ## Daily Use Once set up, just `cd` into the repo. The shell activates automatically: - **PostgreSQL** starts on port 5432 with `prop_dev` and `prop_test` databases created - **`start-services`** / **`stop-services`** commands are available to manually control PostgreSQL - **Mix/Hex** are sandboxed to `.nix-mix` / `.nix-hex` (doesn't pollute `~/.mix`) - **Pre-commit hooks** (mix format, credo, nixfmt, cargo fmt, cargo clippy) install automatically - **Services stop** automatically when you `cd` out of the directory ## Troubleshooting **`direnv: error .envrc is blocked`** Run `direnv allow` in the project directory. **`nix develop` fails with "experimental Nix feature 'nix-command' is disabled"** Add `experimental-features = nix-command flakes` to `~/.config/nix/nix.conf`. **Empty shell, no Elixir available** Run `nix develop --command elixir --version` to see build output. Check for syntax errors in `flake.nix` or `nix/shell.nix`: ```bash nix flake check ``` **Flake can't see new or modified files** Nix flakes only see files tracked by git. If you added a new nix file, stage it first: ```bash git add -N ``` **Nix build fails with a hash mismatch in `shell.nix` (flake-compat)** The `flake-compat` tarball hash in `shell.nix` is stale. Update it to the actual hash shown in the error message. **direnv not triggering on `cd`** Check your shell's rc file has the hook line from step 2. Run `direnv status` in the project directory. **I added a new package to `nix/shell.nix` — how do I reload?** direnv watches `flake.nix` and `flake.lock` for changes and rebuilds automatically. If it doesn't pick up the change, run `direnv reload`. ## Updating Dependencies The flake pins everything via `flake.lock`. To update all inputs to their latest versions: ```bash nix flake update ``` To update just nixpkgs (e.g., to get a newer Erlang/Elixir): ```bash nix flake lock --update-input nixpkgs ``` Commit the updated `flake.lock` so everyone gets the same versions.