The Nix Flake¶
flake.nix is the single source of truth for every tool the project needs:
Postgres + PostGIS, QGIS, the SQL linters, the Python packages, mkdocs and
its plugins, the GDAL/ogr2ogr binaries, and the formatters. Open the
project, cd into it, type nix develop, and you have an environment that
matches CI bit-for-bit.
The contract¶
Anything a developer or CI needs to build, lint, test, or document Infrastructure Mapper is provided by
nix develop. Nopip install, noapt install, nobrew install.
That's an enforced project rule. requirements.txt doesn't exist; CI does
not add packages on top of the Nix shell. Adding a new Python or CLI
dependency means editing flake.nix.
What's inside¶
The shell exposes (see flake.nix for the live list):
| Category | What you get |
|---|---|
| Postgres | postgresql.withPackages [ postgis ] — PG + PostGIS in one binary path. |
| QGIS | From geospatial-nix (provided by imincik/geospatial-nix.repo), with pyqtwebengine, jsonschema, debugpy, future, psutil already wired into the embedded interpreter. LTR is also packaged as qgis-ltr. |
| GDAL / ogr2ogr | Pulled in through the QGIS dependency tree. |
| Python | pkgs.python3.withPackages (ps: [...]) with: mkdocs, mkdocs-material, mkdocs-material-extensions, mkdocs-glightbox, mkdocs-git-revision-date-localized-plugin, mkdocs-mermaid2-plugin, pymdown-extensions, plus the deps used by scripts/*.py. |
| SQL tooling | sqlfluff (Postgres + SQLite profiles), pre-commit. |
| Python tooling | black, ruff (via the dev shell). |
| Markdown / spell | markdownlint-cli, cspell. |
| License compliance | reuse for SPDX header checking. |
| Docs | marp-cli for slide rendering, glow for terminal markdown previews. |
| Visualisation | gource, chafa, ffmpeg. |
| Editing | vim, neovim (via your own config), vscode. |
Everything else (gum, gdb, jq, shellcheck, shfmt, yamllint,
yamlfmt, nixfmt-rfc-style) is there because the pre-commit suite needs
it, or because it's a frequent enough developer aid that it's worth pinning.
Why this is non-negotiable¶
The project's primary product is a database schema. Schema reproducibility hinges on tool reproducibility:
sqlfluff2.x and 3.x disagree on Postgres-keyword handling.blackformatting shifts year to year.mkdocs-materialplugins gain and lose features.ogr2ogrflags drift between GDAL versions.
If CI runs sqlfluff 3.0.0 and you run sqlfluff 2.3.5 locally, your
green commit becomes a red PR. The flake closes that gap: flake.lock
pins every transitive dependency to a content-addressed Nix store path.
nix develop is the same environment for everyone, all the time.
Adding a dependency¶
- Open
flake.nix. - If it's a Python package available in nixpkgs, add it to the
python3.withPackageslist. If it's a CLI tool, add it to thedevShells.${system}.default.packageslist. - Run
nix flake updateif you need newer nixpkgs — otherwise leave the lock file alone. - Run
nix develop --command bash -c 'which <new-tool>'to confirm it's present. - Commit
flake.nixandflake.locktogether.
Don't pip-install a Python package "just to try it." If the experiment is worth keeping, it's worth adding to the flake. If it isn't, it shouldn't be on the developer's path.
The shellHook¶
devShells.${system}.default.shellHook delegates to
scripts/welcome.sh, which prints a gum-styled banner on every entry
showing:
- The current schema version (from
VERSION). - Live Postgres state for
./pgdata— RUNNING, STOPPED, or NOT INITIALIZED — with a coloured chip. - Every
nix run .#…convenience app, grouped by concern (Postgres lifecycle, schema, docs site, apps).
This is intentional — the project rewards discoverability. New
contributors should see the toolkit, and the state of the database, before
they have to go grep for it. The welcome script degrades gracefully to plain
echo if gum isn't on PATH.
CI integration¶
.github/workflows/*.yml all start with:
That's the entire bridge between the flake and CI. The nix-installer-action
is pinned to v22 after we tried v23 and v17 and found CI behaviour
that didn't match local. There's no magic-nix-cache-action, no cachix
— cold Nix every run, deterministic results.
When the flake feels heavy¶
A first nix develop on a fresh machine takes minutes (downloading QGIS,
GDAL, Postgres+PostGIS). Subsequent enters are sub-second. CI takes 30-90
seconds of Nix evaluation per workflow.
The win — "any contributor with Nix can reproduce CI exactly" — is worth that cost. If you don't want to wait, that's a sign you should keep your shell open, not a sign the flake is overweight.