nix-env -q --json | jq -r '.[] | .name' | while read name; do nix-env -qaf '<nixpkgs>' --json "$name" | jq -r 'keys | .[]' | head -n1; done 2>/dev/null
Unfortunately, this is a pretty expensive operation. The problem comes from the fact that nix-env doesn’t remember which attribute or Nixpkgs version you used to install the software. Instead, it just keeps track of the derivation. So, you have to do a search for each name in your current nixpkgs to find the corresponding one. In many cases this will not work. For instance an installed package which is not in Nixpkgs or when two packages have identical names.
An alternative to the above would be keeping track of your software by attribute paths instead of package names. For instance, try this file called env.nix as a starter:
Use buildEnv in enviroment.systemPackages can make nixos-rebuild to update packages in it? I find nix-env cannot do this without a dufferent version for the buildEnv package.