On Mon Aug 24, 2026 at 2:39 PM CDT, Tristan Partin wrote:
> +1
Thanks Tristan, glad to have another Nix user weigh in.
>> A single blessed flake in the tree gives everyone the same reproducible
>> starting point [...]
>
> I am one of the people that has a private copy. I've also been working
> on a NixOS-based buildfarm client that includes a derivation for the
> buildfarm-client code.
That's cool, let's make sure this and that somehow knit up into something
useful. Do you want to share it on this thread or start another one?
>> One deliberate omission: there is no flake.lock.
>
> I think the lack of flake.lock makes sense. I would add it to the
> .gitignore. Additionally, I would also add `/result` and `/result-*` to
> the .gitignore.
Done. Added a small "Nix (see flake.nix)" block to the root .gitignore
covering /flake.lock, /result, and /result-*. Root-anchored so we don't
accidentally ignore a result/ somewhere in the tree.
>> To use it you'll need to be in a Nix environment. This means a Nix-based
>> OS like NixOS or the macOS/Windows layers [...]
>
> Can be Linux as well! For instance, I am using Nix on Fedora, which is
> available in the Fedora system repositories.
Good correction, you're right, and it's an important one. Nix runs anywhere
the package manager is installed; it doesn't require NixOS. I'll fix that
wording in the commit-message/docs framing rather than the code, since the
flake itself is already OS-agnostic and useful in all these locations. As
it happens I use Nix on Fedora on one host, Nix on BSD on another, NixOS
on a separate host and I'm also working to Nix-ify Illumos [1].
>> Flip any single feature (26 toggles) without a preset:
>> nix build --expr '(builtins.getFlake (toString ./.)).packages...'
>
> I didn't know that this was a thing. What a mouthful!
Agreed, it is. It's the escape hatch, not the ergonomic path, most people
will want a preset or their own thin wrapper flake with `.override { ... }`.
I included it only to show the full toggle surface is reachable without
editing the file.
I'm also sure there are ways to add simplified common config into the flake
but I was starting off with something very bland/effective and hopefully
not overly opinionated to gain buy-in.
> I think this will also have side benefits of making things easier to
> test. For instance, we could start inlining buildfarm client members
> configurations as derivations in this repository. [...] Additionally, I
> wonder if NixOS VM tests could expose new ways to do automated testing of
> Postgres.
Both are appealing, and I think they're the real long-term payoff, a
derivation library of animal configs under version control, and NixOS VM
tests for things that are painful to exercise otherwise (replication
topologies, systemd integration, upgrade paths). I'd like to keep v1 to just
the flake so it's easy to review and agree on, then build those out as
separate patches on top. Happy to collaborate!
> Regarding the code, can you explain the reasoning for the packages list
> in the development shell? It seems like everything in the list is
> already included by the Postgres package.
You're right, and thank you, that list was mostly redundant. `inputsFrom =
[ postgresql ]` already pulls in the package's nativeBuildInputs and
buildInputs, so meson, ninja, bison, flex, perl, python3, tcl, and libxslt
were all being listed twice. I've trimmed the devShell down to only what the
package does *not* provide:
- ccache (a dev convenience, not a build input), and
- docbook_xml_dtd_45 + docbook-xsl-nons (the DocBook toolchain, since docs
are off in the default package build, so `nix develop` can build docs
without a separate override).
Verified the trimmed shell still exposes meson/ninja/perl/python3/tcl/libxslt
via inputsFrom, so nothing was actually lost. Will include that in v2.
Thanks again for the careful read.
best.
-gregFrom 0e851da8690e57cff62e79e0722ebb5f2d5086e2 Mon Sep 17 00:00:00 2001
From: Greg Burd <[email protected]>
Date: Mon, 24 Aug 2026 12:53:12 -0400
Subject: [PATCH v2] 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 and add a file that goes stale in
the tree. The flake instead tracks whatever nixpkgs the developer already
runs; anyone needing reproducibility can generate a lock locally.
---
.gitignore | 5 ++
flake.nix | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 262 insertions(+)
create mode 100644 flake.nix
diff --git a/.gitignore b/.gitignore
index 4e911395fe3..e46003ca051 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,8 @@ lib*.pc
/Release/
/tmp_install/
/portlock/
+
+# Nix (see flake.nix)
+/flake.lock
+/result
+/result-*
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