Modern teams juggle between M‑series laptops, Docker‑less CI runners and “tiny” side projects that each need a different Node version. Nix guarantees bit‑for‑bit reproducibility; Devbox hides Nix’s DSL behind a JSON manifest; direnv auto‑activates the env on cd
. The trio erases “works‑on‑my‑machine” forever.
1 Why Nix?
Headache | Nix fix |
---|---|
Global installs collide (brew upgrade node ) |
Functional package manager → every package lives in its own hash path. |
Onboarding new laptop takes a day | Declarative lockfiles re‑create toolchains even years later. |
CI passes, local fails | Deterministic builds—same hash ⇒ same result. |
2 Devbox: Nix power, one‑file UX
Devbox turns a short JSON file into a Nix derivation, builds it into /nix/store/
, prepends only those binaries to $PATH
, and pins exact hashes in devbox.lock
.
// devbox.json – Node example
{
"packages": [
"nodejs@20",
"bun",
"sqlite"
],
"scripts": {
"start": "node index.js",
"test": "bun test"
}
}
Run devbox run start
for non‑interactive or devbox shell
for an interactive env.
CI in two lines
devbox generate github > .github/workflows/ci.yml
git add . && git push
The generated workflow restores only the hashes in devbox.lock
, so cold starts are usually <1 min.
3 Installing everything with one curl (and no Homebrew)
curl -fsSL https://get.jetify.com/devbox | bash
The script installs Devbox and boot‑straps Nix if missing.
After installation, start a fresh shell so $PATH
picks up /usr/local/devbox/bin
.
4 direnv — Auto‑load the env on cd
Instead of asking every teammate to brew/apt direnv, we make Devbox do it globally:
devbox global add direnv # installs direnv once for all projects
eval "$(devbox global shellenv)" # puts global bins in PATH
Global packages live in ~/.devbox/global/devbox.json
and sync across machines.
Create a project‑root .envrc
:
# .envrc
use devbox # provided by Devbox
Approve once:
direnv allow
Now simply cd
into the repo—Node 20, bun, sqlite and any future additions materialise automatically, and vanish on cd ..
.
5 Daily workflow & tips
Scenario | Command |
---|---|
Add a new tool (e.g., eslint ) |
devbox add eslint + commit lockfile |
Update all versions | devbox upgrade → review diff → PR |
Clean disk | sudo nix-collect-garbage -d (local); CI runners auto‑prune. |
New laptop | run bootstrap script below, clone repo, done. |
6 Bootstrap script (copy‑paste)
#!/usr/bin/env bash
set -euo pipefail
# 1. Install Devbox (brings Nix if absent)
curl -fsSL https://get.jetify.com/devbox | bash # jetify installer
# 2. Start a new login shell so $PATH contains devbox
exec $SHELL -l
# 3. Install direnv globally via Devbox
devbox global add direnv # one‑time
# 4. Expose global packages to every shell
if ! grep -q 'devbox global shellenv' ~/.bashrc; then
echo 'eval "$(devbox global shellenv)"' >> ~/.bashrc
fi
# add direnv hook
if ! grep -q 'direnv hook bash' ~/.bashrc; then
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc # for zsh: replace bash→zsh
fi
echo "Reloading shell..."
exec $SHELL -l
Run it once per machine. The next time you git clone
a Devbox‑enabled repo, direnv auto‑loads the exact environment, and CI uses the same hashes—no snowflakes left.
TL;DR
Nix gives deterministic builds.
Devbox makes Nix human‑friendly and CI‑ready.
direnv, installed via
devbox global
, removes the last manual step—envs load/unload automatically.
From fresh laptop to shipping code = one curl & one git clone
.