Nix is a better Docker image builder than Docker's image builder

Advocates of Nix argue it can produce smaller, more reproducible and cache‑friendly container images than traditional Dockerfiles, especially when combined with tools like nix2container or nix‑snapshotter that map Nix store paths directly to image layers or runtime filesystems. Others counter that Nix’s bespoke language, steep learning curve, incomplete package coverage and fragile macOS/cross‑compile stories make it hard to adopt compared to familiar “just shell out and apt-get” Docker workflows, or to alternatives like Bazel, Dagger, Guix, or deterministic Docker registries such as StableBuild. The exchange highlights a broader trade‑off: Nix offers strong guarantees and powerful composability at the cost of complexity and ecosystem maturity, while Docker and similar tools favor ease of use and compatibility but struggle with long‑term reproducibility.

Nix vs. Docker as Image Builders

  • Nix-based builds are praised for declarative, fine‑grained dependency management and tighter reproducibility than typical Dockerfiles.
  • Dockerfiles are criticized for imperceptible non‑determinism (floating tags, apt-get without pinning, git clone of branches), though some argue disciplined use of digests, snapshots, and mirrors can make Docker reproducible too.
  • Several note that Docker’s layer model is hierarchical and oriented around imperative build steps, while Nix maps a dependency graph to layers, enabling more reusable, content‑addressed layers.

Layering, Snapshotters, and Tooling

  • The Docker 128‑layer limit is a real pain when naively mapping Nix store paths to layers; people use heuristics or clumping, which hurts cache reuse.
  • nix-snapshotter integrates Nix with containerd: containers mount directly from the Nix store; docker pull becomes Nix substitution, avoiding tarball duplication and the layer limit. Deployment is straightforward on containerd‑based clusters but trickier on managed k8s.
  • nix2container and Nix’s buildLayeredImage improve caching and registry uploads by streaming layers and storing them in the Nix cache, and by letting users explicitly choose what goes into each layer.

Image Size and Optimization

  • Some report Nix-built images being unexpectedly large (e.g., large Nix base images, full JDKs, glibc with all locales).
  • Others show that with careful use of musl, headless JREs, minimal JREs, and overrides to strip unused features, Nix images can be competitive or small; buildLayeredImage enables sharing large deps (glibc, JDK) across many images.

Developer Experience and Complexity

  • Strong divide: enthusiasts value that a single flake can describe builds, dev shells, Docker images, NixOS modules, and tests; skeptics find flakes and nix language hard to learn, over‑abstracted, and poorly documented.
  • Common complaints: opaque errors, “dark corners,” steep cross‑compilation learning curve, and large, custom flake architectures that overwhelm newcomers.
  • Various attempts to tame complexity are mentioned (flake structuring patterns, higher‑level frameworks, tools like flox), but consensus is that DX remains a major barrier.

Cross‑Platform and Ecosystem Concerns

  • macOS/darwin users face slow or fragile cross‑compilation, missing Hydra caches, and complicated Docker integration; many resort to remote or VM Linux builders.
  • Guix is cited as a similar functional alternative with guix pack -f docker, but suffers from slower package updates and review delays.
  • For simple use cases (e.g., Go/Java services), some argue language‑specific image builders (ko, Jib, Bazel rules_oci) are preferable to the complexity of Nix.