presentations/nix-for-php-developers/slides.md
Oliver Davies d509e167da Automated commit
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-20 19:30:09 +01:00

12 KiB

paginate footer
true oliverdavies.uk

Nix for PHP Developers



Oliver Davies (opdavies)

https://www.oliverdavies.uk


About Me

  • PHP since 2007.
  • Drupal since 2008.
  • Full-time Linux since ~2015.
  • Nix/NixOS since 2022.

bg fit


Who has PHP installed
on their computer?


Who has multiple versions
of PHP installed?


Installing PHP

  • WAMP (Windows), MAMP (macOS), XAMPP
  • Homebrew (brew install php)
  • apt, dnf, yum, pacman yay
  • Laravel Herd/Sail
  • Symfony CLI?
  • Containers (Docker, Podman, LXC, etc)
  • Virtual machines (VMWare, Virtualbox, etc)


What is Nix?

  • Package manager with more than 120,000 packages (nixpkgs)
  • Operating system with more than 20,000 packages (NixOS)
  • Tool for declaratively building software reproducibly
  • A functional domain-specific configuration language
  • Home Manager, nix-darwin, devenv
  • Started as a research project by Eelco Dolstra around 2003




bg fit


Installing Nix

https://nixos.org/download

$ sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) \
  --daemon

Different instructions for Linux, macOS and Windows (WSL2).

Different instructions for NixOS.

$ nix --version

nix (Nix) 2.28.4

This installation tool will set up your computer with the Nix package
manager. This will happen in a few stages:

1. Make sure your computer doesn't already have Nix. If it does, I
   will show you instructions on how to clean up your old install.

2. Show you what I am going to install and where. Then I will ask
   if you are ready to continue.

3. Create the system users (uids [30001..30032]) and groups (gid 30000)
   that the Nix daemon uses to run builds. To create system users
   in a different range, exit and run this tool again with
   NIX_FIRST_BUILD_UID set.

4. Perform the basic installation of the Nix files daemon.

5. Configure your shell to import special Nix Profile files, so you
   can use Nix.

6. Start the Nix daemon.

Installing PHP with Ubuntu

$ apt update -y

$ apt-get install php

$ which php

/usr/bin/php

$ php -v

PHP 8.3.6 (cli) (built: Jul 14 2025 18:30:55)

Running PHP with Nix

$ nix run nixpkgs#php \
  --extra-experimental-features 'nix-command flakes' \
  -- -v

PHP 8.4.11 (cli) (built: Jul 29 2025 15:30:21)
$ nix shell nixpkgs#php \
  --extra-experimental-features 'nix-command flakes'

$ which php
/nix/store/s4kv9bzqawhqcyjg9xm2hji3jap6d6kd-php-with-extensions-8.4.11/bin/php

$ php -v

PHP 8.4.11 (cli) (built: Jul 29 2025 15:30:21)

Using a shell.nix file

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  packages = with pkgs; [
    php
    phpPackages.composer
    phpactor
  ];
}
$ nix-shell shell.nix

[nix-shell:~/my-project]$ composer -V

Composer version 2.8.5 2025-01-21 15:23:40

Using a flake.nix file

{
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";

  outputs = inputs:
    let
      system = "x86_64-linux";
      pkgs = import inputs.nixpkgs { inherit system; };
    in {
      devShells.${system}.default = (import ./shell.nix {
        inherit pkgs;
      });
    };
}

Using a flake.nix file

{
  inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";

  outputs = inputs:
    let
      system = "x86_64-linux";
      pkgs = import inputs.nixpkgs { inherit system; };
    in {
      devShells.${system}.default = pkgs.mkShell {
        packages = with pkgs; [
          php
          phpPackages.composer
          phpactor
        ];
      };
    };
}

Structure of a Flake-based project

.
├── composer.json
├── composer.lock
├── flake.lock
├── flake.nix
├── output_dev
├── source
└── vendor

As well as flake.nix, we also get flake.lock.


Pinning packages

# flake.nix

inputs = {
  nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-24.11";
  nixpkgs-pinned.url = "github:nixos/nixpkgs/45570c299dc2";
}
{
  let
    pkgs-stable = import inputs.nixpkgs-stable { inherit system; };
  in {
    packages = [ pkgs-stable.php ];
  };
}

Managing services

With NixOS:

services.mysql.enable = true;

services.mysql.initialDatabases = [
  { name = "my_project"; }
  { name = "another_project"; }
];

Without NixOS:

https://github.com/juspay/services-flake


Managing services

{
  inputs = {
    flake-parts.url = "github:hercules-ci/flake-parts";

    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";

    process-compose.url = "github:Platonic-Systems/process-compose-flake";

    services.url = "github:juspay/services-flake";
  };

  # ...

Managing services

imports = [
  inputs.process-compose.flakeModule
];

perSystem = { config, lib, pkgs, ... }: {
  process-compose."default" = {
    imports = [
      inputs.services.processComposeModules.default
    ];

    services = { # ... };

    settings.processes = { # ... };
}

Managing services

services = {
  mysql."mysql1" = {
    enable = true;

    initialDatabases = [
      { name = "drupal_nix_flake_example"; }
    ];
  };
};

Managing services

settings.processes = {
  php = {
    command = pkgs.writeShellApplication {
      name = "php-local-server";

      text = "${getExe php} -S 127.0.0.1:${toString webPort} -t web";
    };

    depends_on."mysql1".condition = "process_healthy";
  };
};

Managing services

  devShells.default = pkgs.mkShell {
    inputsFrom = [
      config.process-compose."default".services.outputs.devShell
    ];
  
    nativeBuildInputs = with pkgs; [
      php
      phpPackages.composer
    ];
  };
};

Run nix run . and go to http://localhost:8000.


bg fit


bg fit


Multiple PHPs

  • Laravel Herd/Sail
  • Containers
  • phpenv, brew-php-switcher, phpbrew
  • Vagrant
  • VMWare, VirtualBox
  • Different physical machines?

Nix is like nvm
for everything


My ideal environment

$ php -v

The program 'php' is currently not installed.

$ cd ~/my-project

$ php -v

PHP 8.4.10 (cli) (built: Jul  2 2025 02:22:42)

$ cd ~/another-project

$ php -v

PHP 8.3.24 (cli) (built: Jul 29 2025 15:48:33)

Using direnv

https://direnv.net

It augments existing shells with a new feature that can load and unload environment variables depending on the current directory.


In NixOS:

{
  programs.direnv.enable = true;
  programs.direnv.nix-direnv.enable = true;
}

The .envrc file

If you have a flake.nix:

use flake

Using a remote Flake:

use flake "git+https://code.oliverdavies.uk/opdavies/dev-shells#php84"
use flake "github:opdavies/dev-shells#php84"

Packaging for Nix

stdenv.mkDerivation (finalAttrs: {
  pname = "hello";
  version = "2.12.2";

  src = fetchurl {
    url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
    hash = "sha256-WpqZbcKSzCTc9BHO6H6S9qrluNE72caBm0x6nc4IGKs=";
  };

  env = lib.optionalAttrs stdenv.hostPlatform.isDarwin {
    NIX_LDFLAGS = "-liconv";
  };

  doCheck = true;
  doInstallCheck = true;

  # ...

Packaging for Nix

pkgs.writeShellApplication {
  name = "preview";

  runtimeInputs = with pkgs.nodePackages; [
    browser-sync
  ];

  text = ''
    browser-sync start
      --ignore '**/.*' \
      --no-notify \
      --no-ui \
      -sw
  '';
}

Packaging PHP for Nix

php.buildComposerProject2 (finalAttrs: {
  pname = "phpactor";
  version = "2025.07.25.0";

  src = fetchFromGitHub {
    owner = "phpactor";
    repo = "phpactor";
    tag = finalAttrs.version;
    hash = "sha256-9XWlWwq+xvqPgKIc7IGoMVTxajjYsrPo/ra/0JIE168=";
  };

  vendorHash = "sha256-3xkt0QjytW4BOCgZdevat7zkSuZTPPvwz3yptiq5zoo=";

  # ...

Packaging PHP for Nix

php.buildComposerProject2 (finalAttrs: {
  pname = "pest";
  version = "3.7.4";

  src = fetchFromGitHub {
    owner = "pestphp";
    repo = "pest";
    tag = "v${finalAttrs.version}";
    hash = "sha256-ddsdVx/Vsg7GG11fGASouBU3HAJLSjs1AQGHx52TWzA=";
  };

  composerLock = ./composer.lock;
  vendorHash = "sha256-rOJ6PFp4Xfe89usoH455EAT30d2Tu3zd3+C/6K/kGBw=";

  # ...

Packaging Sculpin

Packaging Sculpin was essentially the same:

https://code.oliverdavies.uk/opdavies/lab/src/branch/main/nix/sculpin

nix build

./result/bin/sculpin generate
.
├── flake.lock
├── flake.nix
├── output_dev
│   └── index.html
└── source
    └── index.md

Thanks!