How a Nix flake made our polyglot stack (and new dev onboarding) fast and sane
TL;DR
- We had a README full of
brewandapt-getcommands. It was brittle and frustrating. On his first day, Lucio (a new hire) felt that frustration and built a Nix flake instead. - Other engineers started using it the next day: onboarding went from 30 minutes to 5, and new devs had a much better first-day experience.
Links: MooseStack repo | MooseStack Nix Flake | NixOS flakes docs
We used to onboard engineers with a README full of brew, apt-get, and curl commands. It was brittle, and a touch frustrating. On his first day, a new dev to our company, Lucio, built a Nix flake to replace that manual set up process.
By the end of that week, a bunch of our developers had adopted it. Setup time dropped from thirty minutes to five, and the onboarding pain dropped just as much.
Readme
After: Nix flake
Lucio introduced a single flake.nix file to replace this README and its manual process. The core of the solution is the devShells.default output, which declaratively defines the complete toolchain.
This file defines all dependencies, from language runtimes down to C libraries like rdkafka and openssl, in one place.
Adoption
The flake.nix PR on a Monday. On Tuesday, another dev from our team, Dave, onboarded. The entire process was git clone and nix develop. He had a fully functional, correct environment in under five minutes (mostly download time) versus the previous 30+ minute manual setup.
This rapid adoption wasn't just about the initial setup; it was a direct result of the technical guarantees.
1. A Standard Interface: The command is nix develop. No more setup guides or per-project instructions.
If you use nix-direnv, it’ll even drop you into the dev shell automatically when you enter the project folder.
2. Atomic Pinning via flake.lock: The flake.lock file is the critical component. It's not just a package-lock.json or a Cargo.lock. It cryptographically pins the exact revisions of nixpkgs, rust-overlay, and all other inputs.
This means a developer six months from now will get the exact same rustc, node, and openssl versions, eliminating environment drift.
Crucially, this also means adjustments to the environment are reproducible. If we need to add pkg-config, we add it to buildInputs, and the updated flake.lock guarantees every other developer gets that exact change when they next run nix develop.
3. Composability: We didn't have to solve Rust tooling in Nix. We just imported a community-maintained solution. The inputs block acts as a package manager for our entire toolchain.
Conclusion
Nix Flakes gave us a reproducible, composable dev environment and cut onboarding time dramatically. They’re not without cost. The syntax takes getting used to, and flakes are still evolving. But, the stability we gained in day-to-day work easily outweighed those bumps: the friction of onboarding and, just as importantly, maintaining complex dev environments was significantly reduced.
Try the same Nix flake we use to build MooseStack in the MooseStack repository.
Interested in learning more?
Sign up for our newsletter — we only send one when we have something actually worth saying.
Related posts
All Blog Posts
OLAP, Product
Ship your data with Moose APIs
You’ve modeled your OLAP data and set up CDC—now it’s time to ship it. Moose makes it effortless to expose your ClickHouse models through typed, validated APIs. Whether you use Moose’s built-in Api class or integrate with Express or FastAPI, you’ll get OpenAPI specs, auth, and runtime validation out of the box.

OLAP
10 Key Takeaways About OLAP — For Telecommunications Operations Leaders
OLAP turns telecom data—from CDRs to telemetry—into instant insight for NOC, field, and care teams. Learn 10 key lessons on how modern OLAP architecture drives real-time visibility, AI-ready analytics, and faster operational decisions across telecom networks.