Onboarding With Devbox Without Learning Nix
The README's setup section has grown to eleven install commands across three operating systems — brew install, apt-get install, a curl | sh for one vendor CLI — and a new engineer's first day ends with protoc-gen-go: program not found or is not executable because step seven was skipped on Linux. Devbox replaces that list with a single devbox.json that pins every tool through Nix, while nobody on the team writes or reads Nix. This page migrates a typical README setup to Devbox, as part of reproducible dev shells with Nix, Devbox and direnv.
The point is not Devbox itself; it is replacing prose instructions with an executable, versioned declaration — the same principle as README-driven automation, applied to the toolchain.
Diagnostic
Measure how far developers' toolchains have already drifted. Run this on several machines and compare:
#!/usr/bin/env bash
set -euo pipefail
for t in node python3 go protoc protoc-gen-go buf jq psql; do
if command -v "$t" >/dev/null; then
v=$("$t" --version 2>&1 | head -1)
printf '%-14s %-40s %s\n' "$t" "$v" "$(command -v "$t")"
else
printf '%-14s MISSING\n' "$t"
fi
done
Expected bad output collected from two laptops:
laptop A: protoc libprotoc 25.1 /opt/homebrew/bin/protoc
laptop A: protoc-gen-go protoc-gen-go v1.34.2 /Users/a/go/bin/protoc-gen-go
laptop B: protoc libprotoc 3.21.12 /usr/bin/protoc
laptop B: protoc-gen-go MISSING
laptop B: psql psql (PostgreSQL) 14.12 /usr/bin/psql
Two major versions of protoc, a missing plugin, and a Postgres client from the distribution's default repository. Generated code will differ between the two machines.
Root cause
Each install instruction resolves to "whatever the package manager has today". Homebrew moves fast, Debian and Ubuntu LTS move slowly, vendor install scripts fetch the latest release, and go install ...@latest installs whatever was tagged that morning. The README captures intent ("install protoc") but not a version, and nothing verifies the result. Over months, every developer's machine becomes a unique combination. The problem is invisible until two machines generate different code or a CI job — with its own, third combination — disagrees with both. Devbox fixes this by pinning each package to an exact version resolved through Nix, recording the resolution in devbox.lock, and making devbox shell the only step a developer runs.
Devbox matters here because the obvious alternative, asking the team to adopt raw Nix, often fails on adoption rather than technology. JSON with name@version entries reads like any other manifest, the commands (add, rm, run, shell) are self-explanatory, and the Nix store is an implementation detail most developers never need to look at.
Resolution
- Install Devbox and initialise the project:
#!/usr/bin/env bash
set -euo pipefail
command -v devbox >/dev/null || curl -fsSL https://get.jetify.com/devbox | bash -s -- -f
devbox init
devbox init creates an empty devbox.json. The first devbox add installs Nix automatically if it is missing.
- Translate each README instruction into a pinned package.
devbox searchshows available versions:
#!/usr/bin/env bash
set -euo pipefail
devbox search protobuf | head -5
devbox add [email protected] [email protected] [email protected] \
[email protected] [email protected] [email protected] [email protected] [email protected]
- Move setup commands into scripts so the README points at them instead of describing them:
{
"packages": {
"nodejs": "20.17.0",
"python": "3.12.5",
"go": "1.22.6",
"protobuf": "25.1",
"protoc-gen-go": "1.34.2",
"buf": "1.39.0",
"jq": "1.7.1",
"postgresql": "16.4"
},
"env": {
"PGHOST": "localhost",
"PGUSER": "postgres"
},
"shell": {
"init_hook": ["test -d node_modules || npm ci --silent"],
"scripts": {
"generate": "buf generate",
"test": "go test ./... && npm test",
"db": "psql shop"
}
}
}
- Shrink the README to three lines:
#!/usr/bin/env bash
set -euo pipefail
cat > README.setup.md <<'EOF'
## Setup
1. Install Devbox: `curl -fsSL https://get.jetify.com/devbox | bash`
2. Run `devbox shell` (or `direnv allow` if you use direnv)
3. Run `devbox run test` — if it passes, you are set up
EOF
- Connect IDEs.
devbox generate direnvwrites an.envrcthat the VS Code and JetBrains direnv plugins read, so the IDE's language servers, test runners and terminal all use the pinned tools.
Expected output
$ devbox run -- bash -c 'protoc --version; protoc-gen-go --version; psql --version'
Info: Ensuring packages are installed.
libprotoc 25.1
protoc-gen-go v1.34.2
psql (PostgreSQL) 16.4
Running the diagnostic from inside devbox shell on both laptops now prints identical versions, and every path begins with /nix/store/ or .devbox/nix/profile.
The first devbox shell on a fresh machine takes a few minutes while packages download from the binary cache; later entries take about a second. That first-run cost is worth measuring and publishing to new hires, because an unexplained five-minute pause is exactly the kind of moment where people abandon the documented path and start installing tools by hand again. A line in the README — "the first run downloads about 1.5 GB and takes 3–5 minutes" — prevents that.
It is also worth checking that the regenerated code is now stable. Run devbox run generate on both laptops and diff the output directories; with the same protoc and plugin versions, the generated files are byte-identical, and the pull requests that used to consist of nothing but churn in generated code disappear. This is often the most visible win for the team, and it is a good metric to share when proposing the change: count the generated-file-only diffs in the last quarter's pull requests before and after.
Prevention
Run CI through Devbox. The
jetify-com/devbox-install-actioninstalls Devbox and caches the Nix store; thendevbox run testuses exactly the laptop toolchain.Reject unpinned additions. A pull-request check that fails when any package in
devbox.jsonhas the valuelatestkeeps the file honest.Keep system package managers out of setup docs. If a tool is needed, it goes in
devbox.json; the onboarding health-check script can warn when a required tool resolves outside the Devbox profile.
Platform caveats
macOS: Devbox installs Nix with a dedicated APFS volume on first use and asks for an administrator password once. On managed Macs, confirm that endpoint-security software allows creating the
/nixvolume.
Apple Silicon (ARM64): nearly all packages are cached for
aarch64-darwin. Ifdevbox addstarts compiling, the requested version is not cached for this platform; choose a nearby cached version withdevbox search.
WSL2: install Devbox inside the Linux distribution, not on Windows. Keep projects in the WSL filesystem for file-watching performance.
Windows (native): Devbox does not support native Windows; use WSL2 or a dev container, for which
devbox generate devcontainerwrites a starting configuration.
Rollback
Devbox does not modify system package managers, so removing it leaves previously installed tools untouched:
#!/usr/bin/env bash
set -euo pipefail
git rm devbox.json devbox.lock .envrc 2>/dev/null || true
rm -rf .devbox
Frequently Asked Questions
Do developers need to understand Nix to use Devbox?
No. Day-to-day use is devbox shell, devbox add and devbox run. Nix knowledge helps only when a package is missing from nixpkgs or needs patching, which one person on the team can handle.
What happens when a package version is not available?
devbox search <name> lists the versions Devbox can resolve. If the exact version is missing, pick the nearest available one, or add a custom Nix flake as a package source in devbox.json.
Can Devbox manage services like Postgres?
Yes, through plugins that start services with devbox services up. For multi-service stacks, most teams keep services in Docker Compose and use Devbox only for CLI tools, which keeps one clear owner for each concern.
How is Devbox different from mise?
mise pins language runtimes and some CLIs by downloading upstream binaries. Devbox pins anything in nixpkgs, including system libraries, through Nix. mise is lighter; Devbox covers more of the toolchain.