weprovide/valet-plus
Valet+ is a batteries-included local dev environment for macOS that extends Laravel Valet with PHP version switching, MariaDB/MySQL, MailHog, Elasticsearch, Xdebug, and ngrok sharing. It gives PHP and Laravel developers a fast, zero-config way to manage multiple sites and services from one CLI.
Valet Plus is a batteries-included fork of Laravel Valet: same .test domain workflow, but with MySQL, Elasticsearch/OpenSearch, Mailhog, Xdebug and multi-PHP switching bundled in — no Docker Compose file or Homestead VM to maintain.
Minimal setup on a fresh machine:
composer global require weprovide/valet-plus
valet-plus install # installs nginx, dnsmasq, php, mysql, etc.
valet-plus start
Then park or link a project and hit it in the browser:
cd ~/Sites/myapp
valet-plus link # or: valet-plus park ~/Sites
valet-plus open myapp # http://myapp.test
Where to look first:
valet-plus --help — the command list is the map of everything the package manages (services, PHP versions, search engines, sharing).~/.config/valet-plus/ — config, per-site nginx confs, drivers and logs. This is where you go when a site 502s.valet-plus status / brew services list + docker ps — the two sources of truth for "is the thing actually running".First use case: point an existing Laravel app at the bundled MySQL by setting DB_HOST=127.0.0.1, DB_DATABASE=myapp, DB_USERNAME=root (empty password by default) and running php artisan migrate.
Service lifecycle as part of the dev loop. Start the day with valet-plus start, and restart individual services rather than the whole stack when you're mid-task:
valet-plus restart nginx
valet-plus restart mysql
valet-plus restart elasticsearch
valet-plus restart opensearch
As of 3.0.4, switching the Elasticsearch version only bounces nginx (not the whole stack), and MySQL restart/stop correctly terminate the running process — so restarting MySQL from a script no longer leaves a stale mysqld holding port 3306.
MySQL connection config. Always use TCP, not the Unix socket:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=root
DB_PASSWORD=
This is the officially supported shape as of 3.0.4 (which switched the default from localhost to 127.0.0.1). Seed scripts, test databases and artisan db:monitor-style tooling should all target the same host string.
Search backends for Scout. Elasticsearch and OpenSearch are switchable per environment; pair the switch with your Scout driver:
valet-plus elasticsearch 7.17
valet-plus opensearch 2
// config/scout.php
'driver' => env('SCOUT_DRIVER', 'elasticsearch'),
OpenSearch v2 is now run through Docker, so docker ps becomes part of your debugging checklist — a stopped Docker daemon looks exactly like a broken search index from the app's perspective.
PHP version switching. Switch globally or per site, and keep the constraint aligned with upstream Valet (3.0.4 tracks laravel/valet's PHP constraint):
valet-plus switch php 8.2
valet-plus switch php 7.4 legacyapp # per-site
Use per-site isolation for legacy projects rather than downgrading the global runtime — otherwise your newer apps break silently.
Mail and Xdebug. Mailhog traps everything on 127.0.0.1:1025:
MAIL_MAILER=smtp
MAIL_HOST=127.0.0.1
MAIL_PORT=1025
Toggle Xdebug only while debugging (valet-plus xdebug on / off); leaving it enabled slows every request and every artisan command.
Scripting the environment. Because service control is CLI-driven, you can encode the whole stack in a project bootstrap script — start services, wait for MySQL to accept connections, migrate, seed, then run the suite. Prefer 127.0.0.1 in the readiness check for the same reason as DB_HOST.
localhost vs 127.0.0.1 for MySQL is the big one. PDO treats localhost as "use the Unix socket", but Valet Plus manages a TCP-bound MySQL. Symptom: SQLSTATE[HY000] [2002] No such file or directory. Fix: DB_HOST=127.0.0.1 everywhere — .env, phpunit.xml, CI env, Docker-adjacent tooling.valet-plus opensearch 2 appears to succeed but queries time out, check the daemon and the mapped port before touching your Scout config. Container restarts lose in-memory state — reindex after a Docker restart.mysqld manually can be removed — and stale-process port conflicts should disappear.laravel/valet. Before composer global update, check the required PHP version; a global upgrade can strand you on a runtime mismatch with your installed Valet. Pin your global PHP via your version manager first.~/.config/valet-plus/Logs/ → is PHP-FPM running for the site's isolated version → valet-plus restart nginx. Most "broken site" reports are an isolated PHP version that isn't installed or a stale FPM socket.~/.config/valet-plus/Nginx/, and custom Valet drivers can be dropped in the drivers directory — both survive valet-plus restart but not a valet-plus install reinstall, so keep them in a dotfiles repo.valet was ever installed globally, the two fight over dnsmasq, ports and the ~/.config tree. Uninstall one completely before switching.How can I help you explore Laravel packages today?