On Tue Aug 25, 2026 at 6:37 AM CDT, Andrew Dunstan wrote:
> Well, "growing" could cover a multitude of possibilities. It could mean
> there was one and now there are two. [...] But if you want to say that
> there is a significant number of people actually contributing here who
> use it that would be all the better for some evidence.

Fair, and I shouldn't have leaned on an unquantified "growing." Let me
separate what I can back up from what I can't.

What I can point to concretely:

  - There is already an active pgsql-hackers thread, "Building with meson on
    NixOS/nixpkgs," [1] where the Meson build was adjusted specifically
    because of problems Nix/NixOS packagers hit. So Nix is already shaping
    build-related decisions here whether or not we carry a flake.
  - Wolfgang Walther maintains the PostgreSQL packaging in nixpkgs and has
    posted here on exactly these issues.
  - Supabase's fork use Nix extensively. [2]
  - I keep a flake setup that I re-apply/use to enable predictable efficient
    development cross-platform.
  - Tristan (upthread) keeps a private flake and a NixOS-based buildfarm
    client.

What I can't do is hand you a survey. I don't have a count of contributors
who develop on Nix, and I'd rather admit that than dress up a guess. If the
bar for this is demonstrated contributor demand, that's a reasonable bar and
I'm happy to let the thread be the evidence, if it's just me and Tristan, so
be it; this can wait.

> Historically we've been fairly resistant to carrying things related to
> how people build or develop postgres.

Understood, and I don't want to relitigate that policy. The narrower claim
I'd make is that a flake is closer to the .editorconfig / .dir-locals.el end
of the spectrum (declare-the-environment) than to endorsing a build system,
it doesn't touch configure, Meson, or the Makefiles. But I take the point
that the door being narrow is deliberate.

On Tue Aug 25, 2026 at 8:19 AM CDT, Tom Lane wrote:
> I might hold my nose if the effects extended only to one more root-level
> file (although that's not great). But if we're talking about rather
> expansive .gitexclude patterns, I'm going to push back on the grounds of
> possible unforeseen side-effects on other peoples' work.

That's a fair objection and easy to remove: v3 (attached) is exactly one new
root-level file, flake.nix, and nothing else. I've dropped the .gitignore
changes entirely.

For what it's worth on side-effects: the patterns I'd proposed were
root-anchored (/flake.lock, /result, /result-*), the same shape as the
existing /tmp_install/ and /portlock/ lines, so they couldn't have matched a
result/ elsewhere in the tree. But that's beside the point now, they're gone.

The build artifacts belong in each developer's own $GIT_DIR/info/exclude,
which is precisely what the .gitignore header already recommends for "files
from local workflows"; `nix build -o` can also just name the symlink. No
committed-ignore changes needed.

So the question really does reduce to your "one more root-level file, though
that's not great." I won't pretend that's nothing. If the consensus is that
even one file is more build/dev tooling than the tree wants to carry, I'll
accept that outcome, but if it's going to live somewhere, one self-contained
file at the root is the smallest footprint I can offer.

best.

-greg

[1] 
https://pg.ddx.io/m/pgsql-hackers/[email protected]/T/
[2] https://github.com/supabase/postgres/blob/develop/flake.nix
From 83273f384bbf7d98418578697c3406e1c0699f73 Mon Sep 17 00:00:00 2001
From: Greg Burd <[email protected]>
Date: Tue, 25 Aug 2026 15:34:06 -0400
Subject: [PATCH v3] Add a Nix flake for reproducible builds and dev shells

Provide a flake.nix at the repository root so contributors on Nix-based
systems (Linux, macOS, and increasingly BSD and illumos) get a single,
in-tree starting point instead of maintaining private, drifting copies.

It doesn't add a build system: `nix develop` drops you into a shell with
bison, flex, perl, the optional libraries, and the docs toolchain on PATH,
where `meson setup` (the default) or `./configure` just works; `nix build`
produces a server.

Every optional configure/Meson feature is a boolean toggle with
platform-appropriate defaults (io_uring, libnuma, systemd, PAM on Linux;
Bonjour on macOS), so it is a starting point, not a policy. Presets cover
debug, minimal, and autoconf builds.

No flake.lock is committed on purpose: pinning nixpkgs would freeze
contributors to one dependency snapshot. The flake instead tracks whatever
nixpkgs the developer already runs; anyone needing reproducibility can
generate a lock locally.

This touches only a single new root-level file. Build artifacts
(flake.lock, result symlinks) are left to each developer's local ignore
($GIT_DIR/info/exclude), as the .gitignore header already recommends for
files from local workflows; `nix build -o` can also name the symlink.
---
 flake.nix | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 257 insertions(+)
 create mode 100644 flake.nix

diff --git a/flake.nix b/flake.nix
new file mode 100644
index 00000000000..7c113cdedc8
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,257 @@
+{
+  description = "PostgreSQL, built from this source tree";
+
+  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+
+  outputs =
+    { self, nixpkgs }:
+    let
+      systems = [
+        "x86_64-linux"
+        "aarch64-linux"
+        "x86_64-darwin"
+        "aarch64-darwin"
+      ];
+      forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
+
+      # A single builder covering every optional feature ./configure and
+      # meson expose. Each feature is a boolean toggle wired to its
+      # buildInput + flag; flip any of them via .override { ... }.
+      # Platform-specific features default to their availability.
+      postgresqlFor =
+        pkgs:
+        let
+          inherit (pkgs) lib stdenv;
+          onLinux = stdenv.hostPlatform.isLinux;
+          onDarwin = stdenv.hostPlatform.isDarwin;
+        in
+        lib.makeOverridable (
+          {
+            # Build system: "meson" (ninja) or "autoconf" (configure/make).
+            # Meson is the default; it is the project's eventual sole build system.
+            buildSystem ? "meson",
+
+            # Optional library features (buildInput + flag).
+            icuSupport ? true,
+            readlineSupport ? true,
+            zlibSupport ? true,
+            opensslSupport ? true,
+            libxmlSupport ? true,
+            libxsltSupport ? true,
+            lz4Support ? true,
+            zstdSupport ? true,
+            uuidSupport ? true,
+            curlSupport ? true,
+
+            # Procedural languages.
+            perlSupport ? true,
+            pythonSupport ? true,
+            tclSupport ? true,
+
+            # Platform-gated features.
+            systemdSupport ? onLinux,
+            selinuxSupport ? false,
+            liburingSupport ? onLinux,
+            numaSupport ? onLinux,
+            gssSupport ? true,
+            ldapSupport ? false,
+            pamSupport ? onLinux,
+            bonjourSupport ? onDarwin,
+            llvmSupport ? false,
+
+            # Developer / build-shape toggles (no extra deps).
+            cassert ? false,
+            debugSymbols ? false,
+            tapTests ? true,
+            injectionPoints ? false,
+
+            # Documentation build (SGML/DocBook toolchain).
+            docs ? false,
+          }:
+          let
+            useMeson = buildSystem == "meson";
+
+            # feature -> { flag = configure arg; dep = buildInput or null; }
+            featureFlag = cond: flag: lib.optional cond flag;
+            featureDep = cond: dep: lib.optional cond dep;
+
+            configureFeatures = lib.flatten [
+              (featureFlag icuSupport "--with-icu")
+              (featureFlag (!icuSupport) "--without-icu")
+              (featureFlag (!readlineSupport) "--without-readline")
+              (featureFlag (!zlibSupport) "--without-zlib")
+              (featureFlag opensslSupport "--with-ssl=openssl")
+              (featureFlag libxmlSupport "--with-libxml")
+              (featureFlag libxsltSupport "--with-libxslt")
+              (featureFlag lz4Support "--with-lz4")
+              (featureFlag zstdSupport "--with-zstd")
+              (featureFlag uuidSupport "--with-uuid=e2fs")
+              (featureFlag curlSupport "--with-libcurl")
+              (featureFlag perlSupport "--with-perl")
+              (featureFlag pythonSupport "--with-python")
+              (featureFlag tclSupport "--with-tcl")
+              (featureFlag systemdSupport "--with-systemd")
+              (featureFlag selinuxSupport "--with-selinux")
+              (featureFlag liburingSupport "--with-liburing")
+              (featureFlag numaSupport "--with-libnuma")
+              (featureFlag gssSupport "--with-gssapi")
+              (featureFlag ldapSupport "--with-ldap")
+              (featureFlag pamSupport "--with-pam")
+              (featureFlag bonjourSupport "--with-bonjour")
+              (featureFlag llvmSupport "--with-llvm")
+              (featureFlag cassert "--enable-cassert")
+              (featureFlag debugSymbols "--enable-debug")
+              (featureFlag tapTests "--enable-tap-tests")
+              (featureFlag injectionPoints "--enable-injection-points")
+            ];
+
+            # meson uses -Dfeature=enabled/disabled instead of --with-*.
+            mesonFeatures = lib.flatten [
+              [ "-Dicu=${if icuSupport then "enabled" else "disabled"}" ]
+              [ "-Dreadline=${if readlineSupport then "enabled" else "disabled"}" ]
+              [ "-Dzlib=${if zlibSupport then "enabled" else "disabled"}" ]
+              [ "-Dssl=${if opensslSupport then "openssl" else "none"}" ]
+              [ "-Dlibxml=${if libxmlSupport then "enabled" else "disabled"}" ]
+              [ "-Dlibxslt=${if libxsltSupport then "enabled" else "disabled"}" ]
+              [ "-Dlz4=${if lz4Support then "enabled" else "disabled"}" ]
+              [ "-Dzstd=${if zstdSupport then "enabled" else "disabled"}" ]
+              [ "-Duuid=${if uuidSupport then "e2fs" else "none"}" ]
+              [ "-Dlibcurl=${if curlSupport then "enabled" else "disabled"}" ]
+              [ "-Dplperl=${if perlSupport then "enabled" else "disabled"}" ]
+              [ "-Dplpython=${if pythonSupport then "enabled" else "disabled"}" ]
+              [ "-Dpltcl=${if tclSupport then "enabled" else "disabled"}" ]
+              [ "-Dsystemd=${if systemdSupport then "enabled" else "disabled"}" ]
+              [ "-Dselinux=${if selinuxSupport then "enabled" else "disabled"}" ]
+              [ "-Dliburing=${if liburingSupport then "enabled" else "disabled"}" ]
+              [ "-Dlibnuma=${if numaSupport then "enabled" else "disabled"}" ]
+              [ "-Dgssapi=${if gssSupport then "enabled" else "disabled"}" ]
+              [ "-Dldap=${if ldapSupport then "enabled" else "disabled"}" ]
+              [ "-Dpam=${if pamSupport then "enabled" else "disabled"}" ]
+              [ "-Dbonjour=${if bonjourSupport then "enabled" else "disabled"}" ]
+              [ "-Dllvm=${if llvmSupport then "enabled" else "disabled"}" ]
+              [ "-Dcassert=${lib.boolToString cassert}" ]
+              [ "-Dtap_tests=${if tapTests then "enabled" else "disabled"}" ]
+              [ "-Dinjection_points=${lib.boolToString injectionPoints}" ]
+            ];
+
+            buildInputs = lib.flatten (with pkgs; [
+              (featureDep icuSupport icu)
+              (featureDep readlineSupport readline)
+              (featureDep zlibSupport zlib)
+              (featureDep opensslSupport openssl)
+              (featureDep libxmlSupport libxml2)
+              (featureDep libxsltSupport libxslt)
+              (featureDep lz4Support lz4)
+              (featureDep zstdSupport zstd)
+              (featureDep uuidSupport libuuid)
+              (featureDep curlSupport curl)
+              (featureDep perlSupport perl)
+              (featureDep pythonSupport python3)
+              (featureDep tclSupport tcl)
+              (featureDep systemdSupport systemdLibs)
+              (featureDep selinuxSupport libselinux)
+              (featureDep liburingSupport liburing)
+              (featureDep numaSupport numactl)
+              (featureDep gssSupport libkrb5)
+              (featureDep ldapSupport openldap)
+              (featureDep pamSupport linux-pam)
+              (featureDep llvmSupport llvmPackages.llvm)
+            ]);
+          in
+          stdenv.mkDerivation {
+            pname = "postgresql";
+            version = "20devel";
+            src = self;
+
+            strictDeps = true;
+
+            nativeBuildInputs = lib.flatten (with pkgs; [
+              bison
+              flex
+              perl
+              pkg-config
+              (featureDep useMeson meson)
+              (featureDep useMeson ninja)
+              (featureDep llvmSupport llvmPackages.llvm.dev)
+              (featureDep docs docbook-xsl-nons)
+              (featureDep docs docbook_xml_dtd_45)
+              (featureDep docs libxslt)
+            ]);
+
+            inherit buildInputs;
+
+            # ---- autoconf path ----
+            configureFlags = lib.optionals (!useMeson) configureFeatures;
+
+            # ---- meson path ----
+            mesonBuildType = "release";
+            mesonFlags = lib.optionals useMeson mesonFeatures;
+            dontUseMesonConfigure = !useMeson;
+            mesonAutoFeatures = "disabled";
+
+            enableParallelBuilding = true;
+            doCheck = tapTests;
+
+            meta = with lib; {
+              description = "Object-relational database management system, built from source";
+              homepage = "https://www.postgresql.org/";;
+              license = licenses.postgresql;
+              platforms = platforms.unix;
+              mainProgram = "psql";
+            };
+          }
+        )
+        { };
+    in
+    {
+      packages = forAllSystems (pkgs: rec {
+        postgresql = postgresqlFor pkgs;
+        # Common presets built on top of the fully-parameterized default.
+        postgresql-autoconf = postgresql.override { buildSystem = "autoconf"; };
+        postgresql-debug = postgresql.override {
+          cassert = true;
+          debugSymbols = true;
+          injectionPoints = true;
+        };
+        postgresql-minimal = postgresql.override {
+          icuSupport = false;
+          readlineSupport = false;
+          zlibSupport = false;
+          opensslSupport = false;
+          libxmlSupport = false;
+          libxsltSupport = false;
+          lz4Support = false;
+          zstdSupport = false;
+          uuidSupport = false;
+          curlSupport = false;
+          perlSupport = false;
+          pythonSupport = false;
+          tclSupport = false;
+          systemdSupport = false;
+          liburingSupport = false;
+          numaSupport = false;
+          gssSupport = false;
+          pamSupport = false;
+        };
+        default = postgresql;
+      });
+
+      # `nix develop`: the postgresql package already brings in the full
+      # build toolchain (meson, ninja, bison, flex, perl, python3, tcl, and
+      # the optional libraries) via inputsFrom. We add only what a dev shell
+      # wants on top: ccache, and the DocBook toolchain for building docs
+      # (docs are off in the default package build).
+      devShells = forAllSystems (pkgs: {
+        default = pkgs.mkShell {
+          inputsFrom = [ self.packages.${pkgs.stdenv.hostPlatform.system}.postgresql ];
+          packages = with pkgs; [
+            ccache
+            docbook_xml_dtd_45
+            docbook-xsl-nons
+          ];
+        };
+      });
+
+      formatter = forAllSystems (pkgs: pkgs.nixfmt);
+    };
+}
-- 
2.54.0

Reply via email to