Daily CLI, flakes, and devShells
Daily CLI, flakes, and devShells
Goal: Make Nix on Fedora your default way to enter project toolchains—with flakes, locks, nix develop, and direnv—so the same workflow continues unchanged on NixOS.
Modern CLI map (muscle memory)
| Task | Command |
|---|---|
| Build package | nix build .#pkg / nix build nixpkgs#hello |
| Run without installing | nix run nixpkgs#cowsay -- hi |
| Temporary tools | nix shell nixpkgs#jq nixpkgs#yq-go |
| Project shell | nix develop |
| Search | nix search nixpkgs ripgrep |
| Eval | nix eval .#foo |
| Flake show | nix flake show |
| Update inputs | nix flake update |
| Metadata | nix flake metadata |
Always prefer nix over nix-env / nix-channel for new work.
First project flake on Fedora
mkdir -p ~/lab/nixos-book/nix-on-linux/demo-flake
cd ~/lab/nixos-book/nix-on-linux/demo-flake
git initflake.nix (pin philosophy: track nixos-26.05 to match this book, or nixpkgs-unstable if you accept drift—commit the lock either way):
{
description = "Fedora bridge demo flake";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
outputs = { self, nixpkgs }:
let
system = "x86_64-linux"; # or: builtins.currentSystem cautiously; prefer explicit
pkgs = import nixpkgs { inherit system; };
in {
packages.${system}.default = pkgs.hello;
devShells.${system}.default = pkgs.mkShell {
packages = with pkgs; [
git
jq
ripgrep
# language example — pick what you actually use:
go_1_24 # adjust attribute to what exists on your pin
# python3
# nodejs_22
];
shellHook = ''
echo "devShell ready on $(uname -sr) — Nix on Linux bridge"
'';
};
};
}Attribute names like go_1_24 change across nixpkgs pins. Use nix search nixpkgs go or nix repl to confirm on your lock. The pattern matters more than the exact attribute.
git add flake.nix
nix flake lock
git add flake.lock
nix develop
# inside shell:
jq --version
rg --version
exitReproducibility check (second machine / second user):
nix develop --offline # after first populate, often works if store warmnix develop vs nix shell vs profile
| Lifetime | Pinned by | Use | |
|---|---|---|---|
nix shell nixpkgs#… |
Shell only | Floating unless flake ref | Quick experiments |
nix develop |
Shell only | flake.lock | Real projects |
nix profile install |
Until removed | Weak unless you pin | Global personal CLIs |
direnv + nix-direnv (high leverage)
Auto-load shells when you cd into a project—same on Fedora and NixOS.
Install tools (profile or HM later)
nix profile install nixpkgs#direnv nixpkgs#nix-direnvdirenvrc
mkdir -p ~/.config/direnv
# Prefer path from nix-direnv package; common pattern:
echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' >> ~/.config/direnv/direnvrcShell hook
bash (~/.bashrc):
eval "$(direnv hook bash)"zsh (~/.zshrc):
eval "$(direnv hook zsh)"Project
cd ~/lab/nixos-book/nix-on-linux/demo-flake
echo 'use flake' > .envrc
direnv allow
cd ..
cd demo-flake # should load shellHook / PATHnix-direnv creates GC roots so nix store gc won’t delete your active shell deps mid-week. Review roots periodically.
Ergonomic extras (optional)
nix profile install \
nixpkgs#nix-output-monitor \
nixpkgs#nix-tree \
nixpkgs#nix-your-shell| Tool | Role |
|---|---|
nom (nix-output-monitor) |
Readable build logs (nom develop, etc.) |
nix-tree |
Why is the store huge? |
nix-your-shell |
Keep zsh/fish inside nix develop |
Example zsh after omz/init:
# if nix-your-shell installed
command -v nix-your-shell >/dev/null && nix-your-shell zsh | source /dev/stdinMulti-system flakes (preview)
Laptops vary (x86_64-linux, aarch64-linux). Pattern:
outputs = { self, nixpkgs }:
let
systems = [ "x86_64-linux" "aarch64-linux" ];
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
in {
devShells = forAllSystems (system:
let pkgs = nixpkgs.legacyPackages.${system};
in {
default = pkgs.mkShell { packages = [ pkgs.jq ]; };
});
};Same flake later grows nixosConfigurations.myhost = … without changing how devShells work.
CI-shaped local check
# Fail if lock missing or eval broken
nix flake check || nix develop -c trueWhen you add packaging later, checks become richer (flake checks).
Lab
- Convert one real project you maintain to
flake.nix+use flakedirenv.
- Commit
flake.lock.
- On a clean shell,
cdinto the project and confirm tools appear via direnv.
- Run
nix flake metadataand paste the lock refreshed time into your journal.
Checkpoint
- You use
nix developdaily for at least one repo
flake.lockis committed
- direnv loads without manual
nix develop
- Profile remains small