Day 7 — Modern CLI fluency
Day 7 — Modern CLI fluency
Stage I · ~4h (theory-heavy + drills)
Goal: Prefer the modern nix CLI for all daily tasks: build, run, develop, shell, flake inspection, store queries—and know which command matches which intent.
Why this day exists
Docs and blog posts mix eras. Muscle memory on the wrong CLI makes flakes feel harder than they are. Today is deliberate fluency so Days 8–10 feel like product work, not archaeology.
Theory 1 — One CLI, many intents
| Intent | Modern command | Rough meaning |
|---|---|---|
Build installable → result |
nix build |
Realize outputs |
| Run app without installing | nix run |
Build/realize + exec |
| Project dev environment | nix develop |
Shell with build inputs (flake devShell) |
| Ad-hoc package shell | nix shell |
Temporary PATH with packages |
| Explore flake outputs | nix flake show |
Schema of outputs |
| Update lock | nix flake update |
Refresh inputs (careful) |
| Metadata / eval | nix eval |
Evaluate expressions |
| Store facts | nix path-info |
Size, refs, sigs |
| Search | nix search |
Find packages |
| Profile (user env) | nix profile |
Generational user installs |
| Format / check (later) | nix fmt, nix flake check |
Quality gates |
Classic cousins (nix-build, nix-shell, …) wait until Day 9.
Theory 2 — Installables: how you name what you want
Modern CLI takes installables:
| Form | Example | Meaning |
|---|---|---|
| Flake output | .#greet |
Current flake, package greet |
| Flake + attr | .#packages.x86_64-linux.greet |
Fully spelled |
| Indirect flake | nixpkgs#hello |
Registry/indirect nixpkgs |
| Git flake | github:NixOS/nixpkgs/nixos-26.05#hello |
Explicit |
| Path flake | ./myproj#default |
Local |
| File / expr | -f file.nix, --expr '…' |
Non-flake (still useful) |
# splits flake ref from attribute
nixpkgs#hello
│ │
│ └─ attribute path inside outputs (with defaults)
└─ flake reference
Theory 3 — nix build deep enough for daily use
nix build .#greet
nix build .#greet --print-out-paths
nix build .#greet -o greet-result
nix build nixpkgs#hello| Flag | Role |
|---|---|
--print-out-paths |
Print store paths |
-o name |
Name the result symlink |
--no-link |
Realize without result |
-L / --print-build-logs |
Stream logs |
--rebuild |
Force rebuild (when applicable) |
Discipline: temporary builds → --no-link or rm result to avoid GC root clutter (Day 2).
Theory 4 — nix run vs nix shell vs nix develop
nix run
nix run nixpkgs#hello
nix run .#greet
nix run nixpkgs#cowsay -- "moo"Builds/downloads if needed, runs the package’s main program, does not require a permanent profile entry.
nix shell
nix shell nixpkgs#git nixpkgs#jq
# temporary shell with git + jq on PATHAd-hoc tools. Great for “I need jq once.”
nix develop
nix develop # .#devShells.default or similar
nix develop .#nameEnters the flake’s devShell—meant for project dependencies, compilers, env vars. Day 8 makes one.
| Command | Sticky? | Typical use |
|---|---|---|
run |
No | One-shot CLI tools |
shell |
Until exit | Ad-hoc package mix |
develop |
Until exit | Project toolchain |
profile install |
Yes | User-global tools (use sparingly early) |
Theory 5 — Flake subcommands
nix flake init # scaffold (optional)
nix flake new mod # template
nix flake show # outputs tree
nix flake metadata # resolved inputs, locks
nix flake check # run checks (later quality)
nix flake update # update all inputs
nix flake update nixpkgs # selective update
nix flake lock # refresh lock without full update semantics as neededshow vs metadata
| Command | Answers |
|---|---|
show |
What outputs exist? |
metadata |
What are inputs pinned to? |
Theory 6 — Eval and debugging eval
nix eval .#packages.x86_64-linux.greet.name
nix eval --raw .#packages.x86_64-linux.greet
nix eval --json nixpkgs#hello.meta | headnix repl
:lf .
:lf nixpkgsREPL remains the best theory laboratory.
Theory 7 — Store queries you will reuse
nix path-info -Sh ./result
nix path-info -rS ./result | tail
nix store gc --dry-run # careful; prefer dry concepts early
nix store delete … # advanced; skip casuallynix-store -q still works; modern path-info is friendlier.
Theory 8 — Profiles without making them a lifestyle
nix profile list
nix profile install nixpkgs#jq
nix profile remove … This volume’s preference: project flakes + devShells over growing a huge imperative profile. Profiles are fine for a few personal tools; they are not a substitute for declarative hosts (Stage II).
Worked examples bank
Example A — Same package, three ways
nix run nixpkgs#hello
nix shell nixpkgs#hello -c hello
nix build nixpkgs#hello --print-out-pathsExample B — Flake introspection
cd ~/lab/90daysofx/02-nixos/day06 # or day07 copy
nix flake show
nix flake metadataExample C — Logs streaming
nix build nixpkgs#hello -LExample D — JSON for scripting
nix flake metadata --json | head -c 400
nix path-info --json ./result | head -c 400Lab 1 — Cheat-sheet construction
mkdir -p ~/lab/90daysofx/02-nixos/day07
cd ~/lab/90daysofx/02-nixos/day07Create CHEATSHEET.md and fill by running each command at least once:
build: …
run: …
shell: …
develop: … (may wait until day08 if no shell yet)
show: …
metadata: …
eval: …
path-info:…
search: …
Paste the exact successful command lines you used.
Lab 2 — Copy day06 flake and operate only with modern CLI
cp -a ~/lab/90daysofx/02-nixos/day06/* ~/lab/90daysofx/02-nixos/day07/ 2>/dev/null || true
# or recreate minimal flake from day06Tasks:
nix flake show
nix build .#greet --print-out-paths
nix run .#greet
nix path-info -rS ./result | tail
rm -f resultand rebuild with--no-link
Lab 3 — Ad-hoc nix shell workflow
nix shell nixpkgs#jq nixpkgs#ripgrep -c bash -c 'jq --version; rg --version'Solve a tiny task: query a JSON blob with jq without installing jq into a profile permanently.
Lab 4 — Search + run loop
nix search nixpkgs cowsay | head
nix run nixpkgs#cowsay -- "modern cli"Record the attribute name you used.
Lab 5 — Intent mapping drill (closed book)
Write the best command for each:
- Temporarily need
ffmpeg
- See outputs of current flake
- Build package without leaving
result
- Run project’s default app
- See what nixpkgs revision lock pins
Common gotchas
| Symptom | Theory |
|---|---|
experimental features errors |
nix-command / flakes not enabled |
| Attribute not found | Wrong system triple / output layout |
nix run can’t find binary |
Package has no main program meta |
Mixing nix-env -i habits |
Prefer run/shell/develop |
flake show empty packages |
system key mismatch |
Slow nix search |
First-time indexing/eval |
Checkpoint
- Cheat-sheet written from real command output
- Can choose run vs shell vs develop correctly
- Built with and without
resultlink
- Used
flake show+metadata
- Used
path-infoon a real path
- No new dependency on classic CLI
Commit
cd ~/lab/90daysofx/02-nixos/day07
git init 2>/dev/null || true
git add .
git commit -m "day07: modern cli cheatsheet drills"Tomorrow
Day 8 — First project flake. Author inputs / outputs / flake.lock properly with devShells.default for a real project directory.