Here's the usual spiel I give to people I mentor to help them contextualize what Nix flakes are for and when to reach for them. (Note: this is not a flakes tutorial, but more of a discussion of where they fit in within the Nix ecosystem)
The way I like to explain it is that Nix flakes are the package manager for Nix.
In other words, if Nix is a package manager for other languages then flakes are the package manager for the Nix language itself.
Nix used to use channels for this purpose, but channels were bad for reasons I won't go into and flakes are the successor to channels. In my view, flakes are a strict improvement over channels and flakes obviate the need for channels. If you find yourself using channels that's a pretty good sign that you should be using flakes instead.
More advanced Nix users might also be familiar with another solution that people used for this purpose: import from derivation. For example: How to fetch Nixpkgs with an empty NIX_PATH. This was a common approach for fixing the inadequacies of Nix channels. "Import from derivation" preceded flakes and nowadays I view flakes also as the successor to "import from derivation" for most use cases. In other words, if you find yourself using "import from derivation" that's also a pretty good sign that you should be using flakes instead.
Once you think of flakes as a package manager for Nix you realize that there are some things you should probably not be using flakes for:
- Managing non-Nix dependencies
- Fetching and locking file/tarball downloads (for things other than Nix code)