How to get postgres man pages in a devShell?

When I look at Nixos Packages search for PostgreSQL 16, I see it lists man pages in the outputs. When I nix shell nixpkgs#postgresql_16 I get the man pages (e.g. man psql).

But in this flak.nix, there’s no man pages for psql, although I get for htop:

{
  description = "Example Go development environment for Zero to Nix";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs"; # also valid: "nixpkgs"
  };

  outputs = { self, nixpkgs }:
    let
      allSystems = [ "x86_64-linux" ];

      nameValuePair = name: value: { inherit name value; };
      genAttrs = names: f: builtins.listToAttrs (map (n: nameValuePair n (f n)) names);
      forAllSystems = f: genAttrs allSystems (system: f {
        pkgs = import nixpkgs { inherit system; };
      });
    in
    {
      # Development environment output
      devShells = forAllSystems ({ pkgs }: {
        default = pkgs.mkShell {
          packages = with pkgs; [
            postgresql_16
            htop
          ];
        };
      });
    };
}

Can you reproduce this in our environment?

What’s going on? Why my devShell drops some man pages?

Yes, here is the minimal flake.nix that I used:

{
  outputs = { self, nixpkgs }:
    let
      system = builtins.currentSystem;
      pkgs = import nixpkgs { inherit system; };
    in
    {
      devShell.${system} = pkgs.mkShell {
        packages = with pkgs; [
          postgresql_16
          htop
        ];
      };
    };
}

(Enter the shell with nix develop --impure, because builtins.currentSystem won’t work otherwise.)

Here is what I observed:

  • The difference between pkgs.postgresql and pkgs.htop is that pkgs.postgresql_16 has multiple outputs. So, while the manpage for htop.1 is in /nix/store/…-htop-3.3.0/share/man, the manpage for psql.1 is in /nix/store/…-postgresql-16.4-man/share/man (notice the -man suffix after the version number in the store path).
  • When entering nix shell nixpkgs#postgresql_16, the nonexistent directory /nix/store/…-postgresql-16.4-man/bin appears in $PATH, which is how the command man psql finds it.
  • When entering nix develop --impure, that nonexistent bin directory is not in $PATH.

At this point, I tried to nix profile install nixpkgs#postgresql_16 and see if the manpage becomes available. I observed that yes, psql.1 is linked to the store from the link farm in ~/.nix-profile/share/man, and obviously ~/.nix-profile/bin is in $PATH, so that’s how man psql finds it.

Looking for a clue on how to get the devShell to link pkgs.postgresql_16’s share/man next to its bin, I opened my ~/.config/nix/profile-flake/flake.nix. Here is how it is implemented internally:

{

  inputs = {
    nixpkgs.url = "flake:nixpkgs";
  };

  outputs = { self, nixpkgs }:
    let
      system = "x86_64-linux";
    in {
      defaultPackage.${system} = let
        pkgs = nixpkgs.legacyPackages.${system};
      in pkgs.buildEnv {
        name = "profile-packages";
        paths = with pkgs; [
          postgresql_16
        ];
      };
  };

}

Et voilà, my minimal flake.nix can be modified slightly, to declare a similar package:

{
  outputs = { self, nixpkgs }:
    let
      system = builtins.currentSystem;
      pkgs = import nixpkgs { inherit system; };
    in
    {
      devShell.${system} = pkgs.mkShell {
        packages = with pkgs; [
          (buildEnv {
            name = "devShell";
            paths = [
              postgresql_16
              htop
            ];
          })
        ];
      };
    };
}

With that, bin and share/man symlinks to both pkgs.postgresql_16 and pkgs.htop are farmed under /nix/store/…-devShell, and man psql works.

Thank you for your detailed answer, @amiryal.

That is a convoluted way to define a devShell in a Flake file. Do you think this should be addressed in nixpkgs instead?

I also tried using nativeBuildInputs instead of packages and had the same results.

packages and nativeBuildInputs are the same thing in a mkShell environment.
And yes it’s a longstanding issue, but I’m not able to find the gh issue at the moment.

[EDIT: workaround was incorrectly tested.]

Also @amiryal, devShell and defaultPackage are deprecated outputs, the current structure is devShells.<system>.default and packages.<system>.default respectively

1 Like