In this blog post, I want to give you some in-depth details about what Herd is, how it works under the hood, and how you can make use of it.
What is Herd?
Herd is a blazing fast, native Laravel and PHP development environment for macOS. It is entirely free to download and use. Herd includes everything you need to get started with Laravel development, including PHP (versions 7.4 up to 8.3 Alpha), nginx and dnsmasq.
You may already use Laravel Valet to serve your local PHP and Laravel sites. Just like Valet, Herd also automatically routes all requests to your local
*.test domains to the correct sites installed on your local machine.
Unlike Valet though, Herd does not have any other dependencies. You do not need Homebrew to get started with PHP, nginx and dnsmasq.
In addition, Herd gives you a UI to manage your sites, secure them via SSL, or isolate their PHP versions.
Migrating from Valet
As Herd internally makes use of Valet itself, we wanted to ensure that migrating from Valet would be really easy. When you install Herd for the very first time, we detect if you are already running and using Laravel Valet and migrate all of your existing Valet settings, isolated sites and SSL certificates to Herd. This allows you to quickly migrate from Valet to Herd. And as Herd does not have any dependencies, switching back to Valet, in case you need to, is as simple as quitting Herd and starting Valet again.
How does it work?
As you may know, if you want to use PHP on your Mac, you usually need to install PHP via Homebrew.
While Homebrew is a great tool, it also adds a lot of overhead - and often complexity, as a simple
brew update command can break your system.
Herd solves this problem by shipping PHP (both CLI and FPM) as statically compiled binaries. Not only does this mean that Herd does not require any additional dependencies on your computer, but the statically compiled PHP binaries also end up being up to 100% faster than traditional PHP versions installed via Homebrew.
The statically compiled PHP binaries result in PHP itself and all of its extensions being compiled into a single binary file.
Herd internally makes use of the static-cli-builder project, maintained by crazywhalecc. During the development of Herd, I also contributed to the project to add support for some extensions that were not yet supported.
As PHP is compiled statically, this means that also all additional (both internal and third-party) PHP extensions need to be compiled statically as well.
Herd's PHP binaries bundle all of the following PHP extensions:
As Herd's PHP binaries are compiled statically it is not possible to use
pecl to install additional PHP extensions out of the box.
You can, however, compile a PHP extension manually and register the
.so file in your
This also works with Xdebug, but we're already working on an automated way to compile Xdebug for all PHP versions that we ship and then bundle it with Herd.
Managing PHP settings
Whenever you may want to change a PHP setting, like the maximum execution time, file upload limits, or memory limits, you usually end up making this change in your
When using a dynamically linked version of PHP, the path to this file is basically "compiled" into PHP itself.
For Herd, this approach was not possible. The PHP binaries of Herd are portable and we do not make any assumptions where our users might end up using these binaries. Using a fixed path for the
php.ini location therefore didn't work.
So how did we solve this?
When PHP tries to find it's
php.ini files, it does this in a specific order.
First, it checks for the given path of the
If other .ini files get "included", they will be read as well.
Last but not least, PHP also searches for an environment variable to find potential
This environment variable is called
PHP_INI_SCAN_DIR and as the name suggests, allows you to define one or multiple directories that PHP should scan for ini files.
When Herd gets installed, this environment variable is automatically written to your
export PHP_INI_SCAN_DIR="/Users/USERNAME/Library/Application Support/Herd/config/php/":$PHP_INI_SCAN_DIR
As Herd is a MacOS app, and all MacOS app have a shared folder for all of their app specific files, we can just hardcode this environment variable.
Automating PHP builds
When you download Herd from the website, the DMG file always includes the most recent stable version of PHP. As of right now, this is version 8.2.
While we all love to work on the most recent PHP versions, some of us have to deal with legacy projects, requiring them to use older versions of PHP.
Because of this, Herd allows you to download additional PHP versions right from within the application UI. The version range that Herd supports is 7.4 - up to the latest 8.3 Alpha 2. This makes it extremely simple and easy to try out the latest Alpha and Beta releases of PHP locally. Just install the new version with one click and you're good to go!
As we do not want to build a new PHP version (for ARM64 and Intel Macs) manually, every time PHP gets updated, we have fully automated this approach.
In order to make this work, there are a couple of components working hand-in-hand:
- A self-hosted GitHub Action runner
- A GitHub action workflow to build PHP binaries
- A Laravel scheduled command to trigger new builds
herd.laravel.com website, we have a scheduled command that checks daily if a new PHP version was released.
If that's the case, it uses the GitHub Actions API to manually trigger a workflow run.
This needs to happen twice - once for ARM64 binaries and once for x86 versions of PHP.
Checking for new PHP versions
In order to check if a new PHP version is actually released, we make use of a nice official "API" that PHP itself provides.
You can make requests to
https://www.php.net/releases/index.php?json&version=VERSION_NUMBER and receive a JSON response containing all of the PHP releases for the given minor version (8.2, 8.1, etc.)
Using this API, we can simply check if the latest version in that JSON file is newer than the latest built version and trigger a new PHP build accordingly.
protected function checkLatestVersion($version)
Why a self-hosted GitHub action runner?
As I mentioned above, we are using a self-hosted GitHub action runner. The main reason for this is because GitHub itself does not offer workflow runners for ARM64 based Macs (M1, M2, etc.). We are using a european based Mac hosting provider called OakHost for this and manually installed and connected a GitHub workflow runner, by following the official documentation.
As we have full control of the Mac hardware, this allows us to not only build the PHP binaries on the server, but also to codesign and notarize them, so that they can be immediately executed once they get downloaded from within Herd itself.
What are you waiting for?
Because of the up-to 100% performance improvements and it's ease of use, Herd has quickly replaced Valet for all of my local development needs.
If you want to give Herd a try yourself, you can visit the Herd website at herd.laravel.com and download Herd yourself.
As Herd is the perfect combination of UI, web-server and Valet sitting in between, there are a couple of very exciting possibilities that Herd unlocks. We are already exploring some of them, and I can't wait to share them with you soon!