A team agrees that "everyone should have the same tools" and then spends a month arguing about how. One engineer wants dev containers because they pin everything, another wants mise because it is fast and simple, and a third has been using Nix for years and cannot understand why anyone would choose anything else. All three approaches work; they pin different amounts of the environment at different costs. This page compares them on the criteria that decide real adoption and gives a way to choose, under reproducible dev shells with Nix, Devbox and direnv.

The comparison assumes a typical product team: a few services in two or three languages, Docker Compose for databases and queues, developers on macOS with some on Linux and Windows.

Diagnostic

Before choosing, find out what actually drifts in your repository today. The approach should fix the drift you have, not the drift you imagine:

#!/usr/bin/env bash
set -euo pipefail
echo "## language runtimes"
for t in node python3 go java ruby; do command -v "$t" >/dev/null && printf '%-8s %s\n' "$t" "$("$t" --version 2>&1 | head -1)"; done
echo "## CLIs"
for t in terraform kubectl helm protoc jq aws; do command -v "$t" >/dev/null && printf '%-10s %s\n' "$t" "$("$t" version 2>/dev/null | head -1 || "$t" --version 2>&1 | head -1)"; done
echo "## system libraries"
pkg-config --modversion openssl libpq 2>/dev/null || echo "pkg-config: not available"

Collect this from five developers and CI, and classify the differences. A typical result:

runtimes:   node differs on 2 of 6 machines, python on 1
CLIs:       terraform differs on 4 of 6, protoc on 3, kubectl on 3
libraries:  openssl 3.0 vs 3.3; libpq 14 vs 16 on 2 machines
Which Drift Each Approach Removes Table showing whether mise, Nix or Devbox, and dev containers pin runtimes, CLIs, system libraries and the OS. Which Drift Each Approach Removes Layer mise Nix, Devbox Dev container Runtimes yes yes yes CLIs many yes yes System libraries no yes yes OS and kernel no no OS yes, kernel no
Each step to the right pins more of the environment and costs more to adopt.

Root cause

The three tools draw the reproducibility boundary in different places. mise (and asdf before it) downloads prebuilt runtimes and CLIs into per-version directories and switches between them based on a .tool-versions or mise.toml file. It is fast and unintrusive, but it relies on the host for everything below the runtime: the C compiler, OpenSSL, libpq, the linker. Nix builds or fetches every package, including those libraries, into an isolated store with a lockfile, so the entire toolchain is pinned while still running natively on the host OS. Dev containers pin a full Linux userland in an image and run development inside it, which also pins the OS distribution — but not the kernel, which comes from the Docker VM, and at the cost of routing file access and editor integration through a container boundary. Teams argue because each person's past pain came from a different layer.

Resolution

  1. Score the approaches against your constraints, not in the abstract. The criteria that decide adoption in practice are onboarding cost, day-to-day speed, how much of the drift found above each one removes, platform coverage, and whether CI can use the same definition:
mise vs Nix Shells at a Glance Comparison of mise and Nix-based shells on adoption cost, speed and coverage. mise vs Nix Shells at a Glance mise Nix or Devbox single binary, TOML file Nix install, /nix volume seconds to adopt an afternoon to adopt runtimes and common CLIs every package and library native Windows supported WSL2 only on Windows
mise is the smallest step; Nix covers more at a higher learning cost.
  1. Pick the smallest approach that removes your actual drift:

    • Only runtimes differ → mise. Add a mise.toml, run mise install, done.
    • CLIs and system libraries differ too, native speed matters → Devbox (or raw Nix if someone on the team knows it well).
    • The team needs an identical Linux userland, uses Codespaces, or has many Windows developers → dev containers.
  2. Combine where it helps rather than forcing one tool everywhere. A common, stable pattern is Nix or Devbox for the toolchain plus Docker Compose for services; or a dev container whose image installs tools with mise, so the same mise.toml works inside and outside the container:

FROM mcr.microsoft.com/devcontainers/base:bookworm
RUN curl -fsSL https://mise.run | MISE_INSTALL_PATH=/usr/local/bin/mise sh
COPY mise.toml /tmp/mise.toml
RUN cd /tmp && mise trust mise.toml && mise install && rm mise.toml
ENV PATH="/root/.local/share/mise/shims:${PATH}"
  1. Make CI use the same definition. Whichever you choose, CI must read the same file: jdx/mise-action for mise, nix develop --command or devbox run for Nix, and devcontainers/ci to run CI steps inside the dev container image. A pinning approach CI ignores only moves the drift.

  2. Write the decision down in an architecture decision record next to the code, with the drift measurement that justified it. When someone proposes switching in a year, the record shows what problem was being solved.

Smallest Approach That Fixes Your Drift Decision diagram choosing mise, Nix or Devbox, or dev containers based on which layers drift. Smallest Approach That Fixes Your Drift What drifts between machines? runtimes only mise CLIs and libraries Nix or Devbox whole OS userland dev containers
Start from the measurement, not from preference.

Expected output

After adopting the chosen approach and wiring it into CI, the diagnostic run on every machine and in CI reports a single version per tool:

node       v20.17.0      (6 of 6 machines)
terraform  v1.9.5        (6 of 6 machines)
protoc     libprotoc 25.1 (6 of 6 machines)
openssl    3.0.14        (6 of 6 machines, Nix/Devbox or container only)

The last line shows the difference in coverage: with mise alone, openssl still reports whatever each host has.

Prevention

  1. Keep one source of truth per repository. Two pinning files — a mise.toml and a devbox.json that both list Node — will disagree within months. If both tools are in use, give each a disjoint set of tools.

  2. Re-measure drift every quarter with the diagnostic script in CI across a matrix of runner images. New drift means something slipped outside the pinned set.

  3. Budget adoption time honestly. mise takes minutes; Devbox an afternoon for the owner and minutes per developer; dev containers a few days to get editor integration, performance and Docker-in-Docker right for a real stack.

Platform caveats

Windows (native): mise runs natively; Nix and Devbox require WSL2; dev containers require Docker Desktop or a WSL2 engine. Teams with many native-Windows developers often land on mise plus dev containers.

macOS: dev containers pay the bind-mount cost on every file access; see choosing between bind mounts and named volumes. mise and Nix run natively with no such cost.

Apple Silicon (ARM64): mise downloads arm64 builds where upstream publishes them and falls back to compiling for some runtimes, such as older Python versions; Nix's cache covers aarch64-darwin well; dev container images must be multi-arch or run under emulation.

Rollback

Each approach is additive and removable independently:

#!/usr/bin/env bash
set -euo pipefail
git rm -q --cached mise.toml devbox.json devbox.lock flake.nix flake.lock 2>/dev/null || true
git rm -rq --cached .devcontainer 2>/dev/null || true
echo "pinning files untracked; restore with git checkout if this was a mistake"

Developers keep whatever tools they had installed; only the shared definition goes away.

Frequently Asked Questions

Is Nix overkill for a small team?

Raw Nix often is, because of the learning curve. Devbox brings Nix's guarantees with a JSON file and familiar commands, which suits small teams well when system libraries or many CLIs drift. If only runtimes drift, mise is enough.

Do dev containers make version managers unnecessary?

Inside the container, yes — the image pins everything. But the image still has to install tools somehow; using mise or Nix inside the Dockerfile keeps the same pinning file usable outside the container and in CI.

Can mise pin system libraries like OpenSSL?

No. mise manages runtimes and tools that ship as standalone binaries or build from source using host libraries. Library versions come from the host, which is the gap Nix and containers close.

Which approach gives the fastest day-to-day experience?

mise and Nix run tools natively, so file access, builds and editor integration are as fast as the host allows. Dev containers add a container boundary, which is negligible on Linux but noticeable for bind-mounted source on macOS and Windows.