Following up on Nix flake with Node and PHP, I needed to enable an extension (in this case, MongoDB). The end result is simple enough, but getting there was a little tricky.
A complete flake
Let me start by posting my complete flake.nix. This supports a composer-based project that has mongodb/mongodb
as a constraint.
1 | { |
Inputs
I’m defining three inputs: nixpkgs
, phps
, and flake-utils
. The NixOS manual calls inputs dependencies; I think of them as package sources:
1 | inputs = { |
These, respectively, are the standard NixOS package repository, the nix-phps repository for older PHP versions, and flake-utils. The latter isn’t essential, but it let me simplify my output syntax.
Outputs
The first thing your output section has to do is accept all the inputs as arguments; they’re passed regardless, and you’ll get an error if you don’t include them:
1 | outputs = { self, nixpkgs, flake-utils, phps }: |
This can happen even if you don’t use them for some reason. Sample error:
1 | error: function 'outputs' called with unexpected argument 'nixpkgs' |
Let…in
There’s a let…in block at the heart of the output declaration. This lets me assign values to names which can then be used within the scope of the block:
1 | outputs = { self, nixpkgs, flake-utils, phps }: |
System
Nix can work crossplatform, but you need to provide some definitions to enable that. This is where flake-utils saves some front matter. This:
1 | flake-utils.lib.eachDefaultSystem (system: |
…is short-hand for this:
1 | allSystems = [ |
PHP
Something I didn’t understand when I was starting on this is that every expression is self-contained. Put simply, it’s not enough to configure and enable the MongoDB extension for the PHP cli binary; I need to do that for composer as well. Therefore, let’s create a resuable expression for PHP that does that:
1 | php74 = (phps.packages.${system}.php74.buildEnv { |
That gives me a PHP 7.4 definition that includes the MongoDB extension.
Shell
I don’t fully grok everything going under the hood here, but I’ll leave breadcrumbs for myself and anyone else. mkShell is an extension of mkDerivation, so it has all the attributes of the latter plus a few of its own. With buildInputs
I’m defining what packages to include; shellHooks
are commands to execute when I run nix develop
to bring up the shell:
1 | devShell = pkgs.mkShell { |
Here, I add both the PHP 7.4 CLI and composer with all default extensions and the MongoDB extension. In the shell hook, I just tell it to run php and output the version when it comes up.