Laravel Valet is a lightweight development environment for macOS. It configures your Mac to run Nginx in the background and uses DnsMasq to proxy all requests on the *.test domain to your local machine.
- macOS
- Homebrew installed
brew install phpbrew install composerSince you're using zsh (default on modern macOS), edit your ~/.zshrc:
echo 'export PATH="$HOME/.composer/vendor/bin:$HOME/.config/composer/vendor/bin:$PATH"' >> ~/.zshrc
source ~/.zshrcNote: Older Composer versions use
~/.composer/vendor/bin, newer ones use~/.config/composer/vendor/bin. Adding both ensures it works regardless.
Verify with:
echo $PATHcomposer global require laravel/valetvalet installThis sets up Nginx, DnsMasq, and registers Valet to launch on system startup.
Verify installation:
which valet
# Should output something like: /Users/<you>/.composer/vendor/bin/valetValet stores its configuration and site data in ~/.config/valet/:
~/.config/valet/
├── config.json # Main config (TLD, paths, PHP version)
├── dnsmasq.d/ # DnsMasq configuration
├── Drivers/ # Custom Valet drivers
├── Extensions/ # Valet extensions
├── Log/ # Nginx & PHP logs
├── Nginx/ # Per-site Nginx configs
├── Sites/ # Linked sites registry
└── Certificates/ # SSL certs for secured sites
valet tld local
# Now sites are served at *.local instead of *.testcat ~/.config/valet/config.jsonThe recommended approach is to create a dedicated directory in your home folder:
# Create a Sites directory in your home folder
mkdir -p ~/Sites
# Park it with Valet (all subdirectories become sites)
cd ~/Sites
valet parkNow every folder inside ~/Sites is automatically served:
~/Sites/my-project→http://my-project.test~/Sites/client-site→http://client-site.test
valet pathscd ~/Sites
valet forgetValet doesn't include a database server. Choose one of the options below.
MariaDB vs MySQL — what's different?
For local WordPress development, nothing changes in practice. MariaDB is a drop-in replacement for MySQL:
- Same SQL syntax, same port (3306), same default credentials
- WordPress
wp-config.phpuses the sameDB_HOST,DB_USER,DB_PASSWORDsettings- WP-CLI commands work identically
- phpMyAdmin works with both without any config changes
- The
mysqlCLI command works with both (MariaDB aliases it)Pick whichever you prefer. Do not install both — they conflict on port 3306.
brew install mariadb
brew services start mariadbDefault credentials after install:
- Host:
127.0.0.1 - User:
root - Password: (empty)
- Port:
3306
Set a root password and remove test databases:
mariadb-secure-installationAfter securing, if you set a root password, use
-pflag:mariadb -u root -p
# Log in
mariadb -u root -p
# Create a database
mariadb -u root -p -e "CREATE DATABASE my_site_db;"
# List all databases
mariadb -u root -p -e "SHOW DATABASES;"
# Drop a database
mariadb -u root -p -e "DROP DATABASE my_site_db;"
# Check status
brew services info mariadbbrew services start mariadb
brew services stop mariadb
brew services restart mariadbbrew install mysql
brew services start mysqlDefault credentials after install:
- Host:
127.0.0.1 - User:
root - Password: (empty)
- Port:
3306
mysql_secure_installationAfter securing, if you set a root password, use
-pflag:mysql -u root -p
# Log in
mysql -u root
# Create a database
mysql -u root -e "CREATE DATABASE my_site_db;"
# List all databases
mysql -u root -e "SHOW DATABASES;"
# Drop a database
mysql -u root -e "DROP DATABASE my_site_db;"
# Check status
brew services info mysqlbrew services start mysql
brew services stop mysql
brew services restart mysqlphpMyAdmin gives you a web UI to manage all your databases. We'll serve it through Valet.
cd ~/Sites
mkdir phpmyadmin
cd phpmyadmincomposer create-project phpmyadmin/phpmyadmin .cp config.sample.inc.php config.inc.phpOpen ~/Sites/phpmyadmin/config.inc.php and update:
<?php
/* Server configuration */
$cfg['Servers'][1]['host'] = '127.0.0.1';
$cfg['Servers'][1]['auth_type'] = 'cookie';
$cfg['Servers'][1]['AllowNoPassword'] = true;
/* Blowfish secret (must be 32 chars for cookie auth) */
$cfg['blowfish_secret'] = 'your-32-character-random-string-here';Generate a random 32-char string:
openssl rand -base64 32Since ~/Sites is parked, phpMyAdmin is already available at:
Log in with:
- Username:
root - Password: (empty, or whatever you set during
mariadb-secure-installation)
valet secure phpmyadminNow at: https://phpmyadmin.test
cd ~/Sites/phpmyadmin
composer updatebrew install wp-clicd ~/Sites
mkdir my-wp-site
cd my-wp-sitewp core downloadmariadb -u root -p -e "CREATE DATABASE my_wp_site;"wp config create \
--dbname=my_wp_site \
--dbuser=root \
--dbpass="your_password" \
--dbhost=127.0.0.1wp core install \
--url="http://my-wp-site.test" \
--title="My WP Site" \
--admin_user=admin \
--admin_password=password \
--admin_email=admin@example.comIf ~/Sites is already parked, your site is live at: http://my-wp-site.test
Admin panel: http://my-wp-site.test/wp-admin
valet secure my-wp-siteNow accessible at: https://my-wp-site.test
Update the URL in WordPress:
wp option update siteurl "https://my-wp-site.test"
wp option update home "https://my-wp-site.test"Save this as ~/Scripts/new-wp-site.sh and make it executable:
#!/bin/bash
# Usage: ./new-wp-site.sh site-name
SITE_NAME=$1
SITES_DIR="$HOME/Sites"
DB_NAME=$(echo "$SITE_NAME" | tr '-' '_')
if [ -z "$SITE_NAME" ]; then
echo "Usage: ./new-wp-site.sh site-name"
exit 1
fi
echo "Creating WordPress site: $SITE_NAME"
# Create directory
mkdir -p "$SITES_DIR/$SITE_NAME"
cd "$SITES_DIR/$SITE_NAME"
# Download WordPress
wp core download
# Create database
mariadb -u root -e "CREATE DATABASE IF NOT EXISTS $DB_NAME;"
# Create config
wp config create \
--dbname="$DB_NAME" \
--dbuser=root \
--dbpass="" \
--dbhost=127.0.0.1
# Install WordPress
wp core install \
--url="http://$SITE_NAME.test" \
--title="$SITE_NAME" \
--admin_user=admin \
--admin_password=password \
--admin_email=admin@example.com
# Secure with HTTPS
valet secure "$SITE_NAME"
# Update URLs for HTTPS
wp option update siteurl "https://$SITE_NAME.test"
wp option update home "https://$SITE_NAME.test"
echo ""
echo "✅ Site ready at: https://$SITE_NAME.test"
echo " Admin: https://$SITE_NAME.test/wp-admin"
echo " User: admin / Password: password"
echo " DB: $DB_NAME (view at https://phpmyadmin.test)"Make it executable:
mkdir -p ~/Scripts
chmod +x ~/Scripts/new-wp-site.shUsage:
~/Scripts/new-wp-site.sh client-projectServes all subdirectories as individual sites:
cd ~/Sites
valet parkAny folder inside ~/Sites becomes accessible at http://folder-name.test.
For projects outside your parked directory:
cd ~/some/other/path/my-project
valet link my-projectAccessible at http://my-project.test.
valet linksvalet unlink my-project| Command | Description |
|---|---|
valet park |
Register current directory for serving |
valet forget |
Unpark the current directory |
valet paths |
View all parked paths |
valet link [name] |
Serve current directory at name.test |
valet links |
List all linked sites |
valet unlink [name] |
Remove a link |
valet secure [name] |
Serve a site over HTTPS |
valet unsecure [name] |
Revert to HTTP |
valet share |
Share your site publicly via a tunnel |
valet restart |
Restart Valet services |
valet stop |
Stop all Valet services |
valet start |
Start Valet services |
valet use php@8.2 |
Switch PHP version |
valet tld [tld] |
Change the TLD (default: test) |
valet log |
View Valet logs |
valet which |
Show which Valet driver serves current site |
# Install another PHP version
brew install php@8.1
# Tell Valet to use it
valet use php@8.1
# Switch back
valet use php@8.3Create a .valetphprc file in your site root:
echo "php@8.1" > ~/Sites/legacy-project/.valetphprc# Remove the link/site
valet unlink my-wp-site
# or if using park, just delete the folder
# Drop the database
mariadb -u root -e "DROP DATABASE my_wp_site;"
# Remove the directory
rm -rf ~/Sites/my-wp-site
# Remove SSL cert if secured
valet unsecure my-wp-siteValet command not found:
# Check if composer bin is in PATH
echo $PATH | tr ':' '\n' | grep composer
# If not, re-add it
echo 'export PATH="$HOME/.composer/vendor/bin:$HOME/.config/composer/vendor/bin:$PATH"' >> ~/.zshrc
source ~/.zshrcSites not resolving:
valet restart
# or
sudo valet restartPing test:
ping anything.test
# Should resolve to 127.0.0.1Check service status:
brew services listMariaDB "Access denied for root" (ERROR 1698):
This happens when MariaDB uses unix_socket authentication for root (common on Linux installs). Only the system root user can log in as MariaDB root.
Quick fix — use sudo:
sudo mariadb -u rootPermanent fix — switch root to password auth:
sudo mariadb -u rootALTER USER 'root'@'localhost' IDENTIFIED BY 'your_password';
FLUSH PRIVILEGES;
EXIT;Now log in without sudo:
mariadb -u root -pAlternative — create a dedicated dev user (recommended):
sudo mariadb -u rootCREATE USER 'dev'@'localhost' IDENTIFIED BY 'dev';
GRANT ALL PRIVILEGES ON *.* TO 'dev'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;Then use dev / dev as credentials in wp-config.php and WP-CLI commands:
mariadb -u dev -pdev
wp config create --dbuser=dev --dbpass=dev ...MariaDB won't start:
brew services restart mariadb
# Check logs
cat /opt/homebrew/var/mysql/*.errMySQL won't start:
brew services restart mysql
# Check logs
cat /opt/homebrew/var/mysql/*.errPermission issues:
sudo valet trustphpMyAdmin shows "Access denied":
Make sure AllowNoPassword is set to true in config.inc.php, or use the password you set during mariadb-secure-installation.
valet stop
valet uninstall
composer global remove laravel/valet
brew uninstall nginx dnsmasq