diff --git a/nix-for-php-developers/.gitignore b/nix-for-php-developers/.gitignore
new file mode 100644
index 0000000..9b61c8c
--- /dev/null
+++ b/nix-for-php-developers/.gitignore
@@ -0,0 +1 @@
+/*.html
diff --git a/nix-for-php-developers/NixOS.png b/nix-for-php-developers/NixOS.png
new file mode 100644
index 0000000..99cdeea
Binary files /dev/null and b/nix-for-php-developers/NixOS.png differ
diff --git a/nix-for-php-developers/book.png b/nix-for-php-developers/book.png
new file mode 100644
index 0000000..f377a7e
Binary files /dev/null and b/nix-for-php-developers/book.png differ
diff --git a/nix-for-php-developers/drupal-install.png b/nix-for-php-developers/drupal-install.png
new file mode 100644
index 0000000..2853d58
Binary files /dev/null and b/nix-for-php-developers/drupal-install.png differ
diff --git a/nix-for-php-developers/nix-logo.png b/nix-for-php-developers/nix-logo.png
new file mode 100644
index 0000000..819402a
Binary files /dev/null and b/nix-for-php-developers/nix-logo.png differ
diff --git a/nix-for-php-developers/nix-search-php.png b/nix-for-php-developers/nix-search-php.png
new file mode 100644
index 0000000..a35c2f2
Binary files /dev/null and b/nix-for-php-developers/nix-search-php.png differ
diff --git a/nix-for-php-developers/nix-search-php2.png b/nix-for-php-developers/nix-search-php2.png
new file mode 100644
index 0000000..74848cf
Binary files /dev/null and b/nix-for-php-developers/nix-search-php2.png differ
diff --git a/nix-for-php-developers/nix-search.png b/nix-for-php-developers/nix-search.png
new file mode 100644
index 0000000..c5ca2b4
Binary files /dev/null and b/nix-for-php-developers/nix-search.png differ
diff --git a/nix-for-php-developers/process-compose.png b/nix-for-php-developers/process-compose.png
new file mode 100644
index 0000000..e886824
Binary files /dev/null and b/nix-for-php-developers/process-compose.png differ
diff --git a/nix-for-php-developers/repology.png b/nix-for-php-developers/repology.png
new file mode 100644
index 0000000..e68609f
Binary files /dev/null and b/nix-for-php-developers/repology.png differ
diff --git a/nix-for-php-developers/slides.md b/nix-for-php-developers/slides.md
new file mode 100644
index 0000000..38a6e25
--- /dev/null
+++ b/nix-for-php-developers/slides.md
@@ -0,0 +1,803 @@
+---
+paginate: true
+footer: 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.
+
+
+
+---
+
+
+
+
+
+
+
+---
+
+
+
+# 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
+
+
+
+---
+
+
+
+
+
+
+
+---
+
+
+
+
+
+---
+
+
+
+
+
+---
+
+
+
+
+
+
+
+---
+
+# Installing Nix
+
+https://nixos.org/download
+
+```sh
+$ 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.
+
+```sh
+$ 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
+
+```shell
+$ 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
+
+```shell
+$ nix run nixpkgs#php \
+ --extra-experimental-features 'nix-command flakes' \
+ -- -v
+
+PHP 8.4.11 (cli) (built: Jul 29 2025 15:30:21)
+```
+
+```shell
+$ 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
+
+```nix
+{ pkgs ? import {} }:
+
+pkgs.mkShell {
+ packages = with pkgs; [
+ php
+ phpPackages.composer
+ phpactor
+ ];
+}
+```
+
+```shell
+$ 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
+
+```nix
+{
+ 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
+
+```nix
+{
+ 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
+
+```shell
+.
+├── composer.json
+├── composer.lock
+├── flake.lock
+├── flake.nix
+├── output_dev
+├── source
+└── vendor
+```
+
+
+
+As well as **flake.nix**, we also get **flake.lock**.
+
+---
+
+# Pinning packages
+
+```nix
+# 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";
+}
+```
+
+```nix
+{
+ let
+ pkgs-stable = import inputs.nixpkgs-stable { inherit system; };
+ in {
+ packages = [ pkgs-stable.php ];
+ };
+}
+```
+
+
+
+---
+
+# Managing services
+
+With NixOS:
+
+```nix
+services.mysql.enable = true;
+
+services.mysql.initialDatabases = [
+ { name = "my_project"; }
+ { name = "another_project"; }
+];
+```
+
+
+
+Without NixOS:
+
+
+
+---
+
+# Managing services
+
+```nix
+{
+ 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
+
+```nix
+imports = [
+ inputs.process-compose.flakeModule
+];
+
+perSystem = { config, lib, pkgs, ... }: {
+ process-compose."default" = {
+ imports = [
+ inputs.services.processComposeModules.default
+ ];
+
+ services = { # ... };
+
+ settings.processes = { # ... };
+}
+```
+
+---
+
+# Managing services
+
+```nix
+services = {
+ mysql."mysql1" = {
+ enable = true;
+
+ initialDatabases = [
+ { name = "drupal_nix_flake_example"; }
+ ];
+ };
+};
+```
+
+---
+
+# Managing services
+
+```nix
+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
+
+```nix
+ 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.
+
+---
+
+
+
+
+
+---
+
+
+
+
+
+---
+
+# 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
+
+```shell
+$ 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:
+
+```nix
+{
+ programs.direnv.enable = true;
+ programs.direnv.nix-direnv.enable = true;
+}
+```
+
+---
+
+# The .envrc file
+
+If you have a `flake.nix`:
+
+```bash
+use flake
+```
+
+Using a remote Flake:
+
+```bash
+use flake "git+https://code.oliverdavies.uk/opdavies/dev-shells#php84"
+```
+
+```bash
+use flake "github:opdavies/dev-shells#php84"
+```
+
+---
+
+# Packaging for Nix
+
+```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
+
+```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
+
+```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
+
+```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
+
+```shell
+nix build
+
+./result/bin/sculpin generate
+```
+
+```shell
+.
+├── flake.lock
+├── flake.nix
+├── output_dev
+│ └── index.html
+└── source
+ └── index.md
+```
+
+
+
+---
+
+# Thanks!
+
+- https://nixos.org
+- https://github.com/nixos/nixpkgs
+- https://wiki.nixos.org/wiki/PHP
+- https://nixos.org/manual/nixpkgs/stable/#ssec-building-php-projects
+- https://code.oliverdavies.uk/opdavies/lab
+- https://code.oliverdavies.uk/opdavies/drupal-nix-flake-example
+- https://code.oliverdavies.uk/opdavies/nix-config (laptop and home server)
+- https://books.oliverdavies.uk/nix-for-php-developers (book, in progress)