Why
Still writing a long project README that tells people what to install — versions, tools, footnotes — and it goes stale every week?
Or a setup script that “just works” on your machine and fails on everyone else’s?
Or you clone a repo and burn half a day before anything runs — turns out it needed Java 8, and somebody forgot to put that in the README?
Or your CONTRIBUTING doc is basically another product — pages of setup, then “ask in Slack”?
Or you jump between many projects — old and new — and the versions fight: Go, Python, Terraform, JDK, kubectl — plus a pile of version managers that never quite agree?
That pain is the why you should use Nix.
Sounds too good to be true? Maybe. You might hit one or two hiccups the first time you install Nix or follow this post. I am a user of Nix — not a Nix contributor — and I only tried this write-up on a Mac. So I expect a clean path for most Mac users, but not a perfect guarantee on every machine. A couple of bumps should not stop you.
Because Nix — it is really worth it, especially in today’s agentic coding world.
If you hate Nix — or you are new to it
Either way, this blog is for you.
The old objection was real: alien syntax, loud errors, a side quest you never asked for. That barrier is mostly gone. Nix collapses the mess above into a declared, project-scoped toolchain. AI collapses the excuse that writing Nix was too hard. You list what the project needs. AI writes flake.nix. You run nix develop and work.
A README is not the enemy. You can still keep one — even generate an honest setup section from the flake. The difference is the source of truth is flake.nix, not a paragraph someone forgot to update.
This post walks toward a stack with many dependencies (Go, Python, Scala, Postgres, …). It does not ask you to install any of that by hand.
Stop writing a long README on how to set up the project locally
Once the team has Nix, setup is this:
cd my-project
nix develop # or: nix develop -c zsh
Done. Dusted. If you want a short README, generate it from the flake — don’t hand-maintain a lying install novel. Refuse Nix if you want — keep the version managers. Up to you.
Install Nix quickly (macOS)
curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh
Enable flakes if needed (~/.config/nix/nix.conf):
experimental-features = nix-command flakes
Other platforms: https://nixos.org/download/.
A hello-world you can try today
Tiny Scala/sbt project. Do not install sbt. Do not install a JDK. If they are missing on your machine, that is fine — nix develop brings them in from the flake.
Drop these files in a folder (hello-nix):
build.sbt:
ThisBuild / scalaVersion := "2.13.16"
ThisBuild / version := "0.1.0"
lazy val root = (project in file("."))
.settings(
name := "hello-nix",
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test
)
src/main/scala/Hello.scala:
object Hello {
def main(args: Array[String]): Unit =
println("hello from a Nix-managed JDK + sbt")
}
flake.nix (or ask AI to generate it):
{
description = "Hello Nix — sbt + JDK dev shell";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
outputs = { self, nixpkgs }:
let
systems = [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" "aarch64-linux" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f (
import nixpkgs { inherit system; }
));
in {
devShells = forAllSystems (pkgs: {
default = pkgs.mkShell {
packages = [
pkgs.jdk21
pkgs.sbt
];
};
});
};
}
Then:
nix flake lock
nix develop
java -version
sbt run
That is the point. nix develop did the installing. The JDK and sbt on your PATH come from this flake — not from a global install you managed by hand.
A separate legacy project: older versions on purpose
Same idea, older pin (hello-nix-legacy):
{
description = "Legacy hello — older JDK + sbt via an older nixpkgs";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
outputs = { self, nixpkgs }:
let
systems = [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" "aarch64-linux" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f (
import nixpkgs { inherit system; }
));
in {
devShells = forAllSystems (pkgs: {
default = pkgs.mkShell {
packages = [
pkgs.jdk17
pkgs.sbt
];
};
});
};
}
cd hello-nix && nix develop # JDK 21 world
cd hello-nix-legacy && nix develop # JDK 17 world
Different directories. Different versions. No global fight.
Ask AI for the next flake
You just saw flake.nix. Growing is not “learn Nix philosophy first.”
What does this project depend on? List it. Hand the list to AI. Review. Commit.
Go, Python, Terraform, kubectl, Docker, sbt, Node, cloud CLIs — whatever. That is the whole authoring loop.
A more convincing project: polyglot local
When one repo needs several languages and a real database, the pitch stops being abstract.
Example in this repo: examples/polyglot-local.
One flake: JDK 21 + sbt (ZIO HTTP), Go 1.23, Python 3.12 + Flask, PostgreSQL 16.
cd examples/polyglot-local
nix develop # or: nix develop -c zsh
./run-all-servers.sh
curl -s http://127.0.0.1:8080/
run-all-servers.sh only starts processes. The Go and Python APIs create the table, insert, and read. Scala aggregates both.
Ctrl+C and you are safe: no global “I installed Go/Python/Postgres forever” mutation. Leave nix develop, and that toolchain leaves your shell.
This is not “Nix instead of Docker.” Use Docker with Nix when you want. Ship to k8s when you want. Nix declares the toolchain; Docker/k8s run and schedule. Pick both when both help.
Keep your zsh
nix develop -c zsh
Or in ~/.zshrc:
nix() {
if [[ $1 == "develop" ]]; then
shift
command nix develop -c zsh "$@"
else
command nix "$@"
fi
}
A short honest note at the end
I said AI made Nix simple so the hate camp would listen. Fair bait.
Honestly: I never thought Nix was the villain. I loved it in 2020 (old post), I love it now, and I will keep loving it. I love FP — Scala, Java, or Go, the philosophy sticks. For me, immutability and declared inputs do not stop at the function boundary — they belong in system design and local setup too. Knowing FP and still writing Java always worked for me.
AI lowers the door for everyone else. The values were already right.
Internals (store, profiles, generations, GC): Nix Internals — What’s Happening Under the Hood.
This website is Nix too
git clone https://github.com/afsalthaj/afsalthaj.github.io.git
cd afsalthaj.github.io
nix develop # or: nix develop -c zsh
npm install
npm run dev