Day 7 — Modern CLI fluency

Updated

July 30, 2026

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 PATH

Ad-hoc tools. Great for “I need jq once.”

nix develop

nix develop                 # .#devShells.default or similar
nix develop .#name

Enters 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 needed

show 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 | head
nix repl
:lf .
:lf nixpkgs

REPL 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 casually

nix-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-paths

Example B — Flake introspection

cd ~/lab/90daysofx/02-nixos/day06   # or day07 copy
nix flake show
nix flake metadata

Example C — Logs streaming

nix build nixpkgs#hello -L

Example D — JSON for scripting

nix flake metadata --json | head -c 400
nix path-info --json ./result | head -c 400

Lab 1 — Cheat-sheet construction

mkdir -p ~/lab/90daysofx/02-nixos/day07
cd ~/lab/90daysofx/02-nixos/day07

Create 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 day06

Tasks:

  1. nix flake show
  2. nix build .#greet --print-out-paths
  3. nix run .#greet
  4. nix path-info -rS ./result | tail
  5. rm -f result and 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:

  1. Temporarily need ffmpeg
  2. See outputs of current flake
  3. Build package without leaving result
  4. Run project’s default app
  5. 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 result link
  • Used flake show + metadata
  • Used path-info on 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.