Laravel Sail has made local development much more straightforward, but there's more to explore beyond the basics. Here's how to set up a more robust local environment that can grow with your project and work well for teams.
This guide assumes basic Docker knowledge. If you're new to containerization, start with Docker's official documentation.
Why Sail Over Native Development?
Consistency
Every team member runs identical environments. No more "works on my machine" issues.
Isolation
Multiple projects with different PHP/Node versions run without conflicts.
Production Parity
Development closely mirrors production infrastructure, reducing deployment surprises.
Advanced Sail Configuration
Custom Docker Compose Override
Create a docker-compose.override.yml
for team-specific configurations:
# docker-compose.override.yml
version: '3'
services:
laravel.test:
volumes:
# Performance: Use delegated volumes on macOS
- './:/var/www/html:delegated'
# SSH agent forwarding for Git operations
- '${SSH_AUTH_SOCK}:/ssh-agent'
environment:
- SSH_AUTH_SOCK=/ssh-agent
# Custom PHP configuration
- PHP_POST_MAX_SIZE=100M
- PHP_UPLOAD_MAX_FILESIZE=100M
- PHP_MEMORY_LIMIT=512M
# Additional ports for debugging
ports:
- '${APP_PORT:-80}:80'
- '9003:9003' # Xdebug
# Redis for caching and sessions
redis:
image: 'redis:alpine'
ports:
- '${REDIS_PORT:-6379}:6379'
volumes:
- 'sail-redis:/data'
networks:
- sail
healthcheck:
test: ["CMD", "redis-cli", "ping"]
retries: 3
timeout: 5s
# Elasticsearch for search functionality
elasticsearch:
image: 'elasticsearch:8.8.0'
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- '${ELASTICSEARCH_PORT:-9200}:9200'
volumes:
- 'sail-elasticsearch:/usr/share/elasticsearch/data'
networks:
- sail
# MinIO for S3-compatible object storage
minio:
image: 'minio/minio:latest'
ports:
- '${MINIO_PORT:-9000}:9000'
- '${MINIO_CONSOLE_PORT:-8900}:8900'
environment:
MINIO_ROOT_USER: sail
MINIO_ROOT_PASSWORD: password
volumes:
- 'sail-minio:/data/minio'
networks:
- sail
command: minio server /data/minio --console-address ":8900"
volumes:
sail-redis:
driver: local
sail-elasticsearch:
driver: local
sail-minio:
driver: local
Custom PHP Configuration
Create docker/php/php.ini
for production-like PHP settings:
[PHP]
; Production-like settings
expose_php = Off
memory_limit = 512M
post_max_size = 100M
upload_max_filesize = 100M
max_execution_time = 300
max_input_vars = 3000
; Error handling (adjust for development)
display_errors = On
display_startup_errors = On
log_errors = On
error_log = /var/log/php_errors.log
; OPcache settings
opcache.enable = 1
opcache.memory_consumption = 128
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2
opcache.save_comments = 1
; Session configuration
session.gc_maxlifetime = 1440
session.cookie_httponly = 1
session.cookie_secure = 0
session.use_strict_mode = 1
; File uploads
file_uploads = On
upload_tmp_dir = /tmp
; Date settings
date.timezone = UTC
Xdebug Configuration for Development
Add Xdebug configuration to docker/php/xdebug.ini
:
[xdebug]
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.start_with_request=yes
xdebug.discover_client_host=1
xdebug.idekey=VSCODE
Performance Optimization
macOS Volume Performance
macOS Docker performance can be slow. Here are several optimization strategies:
1. Use :delegated Volume Mounts
volumes:
- './:/var/www/html:delegated'
2. Exclude Heavy Directories
# .dockerignore
node_modules
.git
vendor
storage/logs/*
storage/framework/cache/*
storage/framework/sessions/*
storage/framework/views/*
3. Use Named Volumes for Dependencies
volumes:
- './:/var/www/html:delegated'
- 'sail-node_modules:/var/www/html/node_modules'
- 'sail-vendor:/var/www/html/vendor'
Database Performance Tuning
Optimize MySQL for development with custom configuration:
# docker/mysql/my.cnf
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# Performance settings
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
# Query cache
query_cache_type = 1
query_cache_size = 32M
query_cache_limit = 2M
# Connection settings
max_connections = 100
wait_timeout = 600
interactive_timeout = 600
# Logging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# Disable DNS lookups
skip-name-resolve
Production-Ready Environment Variables
Structure your .env
file for consistency:
# Application
APP_NAME="My Laravel App"
APP_ENV=local
APP_KEY=base64:YOUR_APP_KEY
APP_DEBUG=true
APP_URL=http://localhost
# Sail Configuration
APP_PORT=80
VITE_PORT=5173
WWWGROUP=1000
WWWUSER=1000
# Database
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=sail
DB_PASSWORD=password
# Redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
# Mail (using Mailpit for local development)
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
# S3 Compatible Storage (MinIO)
AWS_ACCESS_KEY_ID=sail
AWS_SECRET_ACCESS_KEY=password
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=local
AWS_USE_PATH_STYLE_ENDPOINT=true
AWS_ENDPOINT=http://minio:9000
AWS_URL=http://localhost:9000/local
# Search (Elasticsearch)
SCOUT_DRIVER=elasticsearch
ELASTICSEARCH_HOST=elasticsearch:9200
# Logging
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
# Broadcasting
BROADCAST_DRIVER=log
CACHE_DRIVER=redis
FILESYSTEM_DISK=local
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
Team Collaboration Best Practices
Git Hooks for Consistency
Create .githooks/pre-commit
to ensure code quality:
#!/bin/bash
echo "Running pre-commit checks..."
# Check if Sail is running
if ! ./vendor/bin/sail ps | grep -q "Up"; then
echo "โ Sail containers are not running. Please start with: ./vendor/bin/sail up -d"
exit 1
fi
# Run PHP CS Fixer
echo "๐ง Running PHP CS Fixer..."
./vendor/bin/sail exec laravel.test ./vendor/bin/php-cs-fixer fix --dry-run --diff
if [ $? -ne 0 ]; then
echo "โ PHP CS Fixer found issues. Run: ./vendor/bin/sail exec laravel.test ./vendor/bin/php-cs-fixer fix"
exit 1
fi
# Run PHPStan
echo "๐ Running PHPStan..."
./vendor/bin/sail exec laravel.test ./vendor/bin/phpstan analyse
if [ $? -ne 0 ]; then
echo "โ PHPStan found issues."
exit 1
fi
# Run tests
echo "๐งช Running tests..."
./vendor/bin/sail test
if [ $? -ne 0 ]; then
echo "โ Tests failed."
exit 1
fi
echo "โ
All checks passed!"
Makefile for Common Tasks
Create a Makefile
for consistent commands:
.PHONY: install start stop restart test migrate fresh seed backup
# Installation and setup
install:
@echo "๐ Setting up Laravel project..."
cp .env.example .env
./vendor/bin/sail up -d
./vendor/bin/sail composer install
./vendor/bin/sail artisan key:generate
./vendor/bin/sail npm install
./vendor/bin/sail npm run build
make migrate
@echo "โ
Project setup complete!"
# Container management
start:
./vendor/bin/sail up -d
stop:
./vendor/bin/sail down
restart:
./vendor/bin/sail down
./vendor/bin/sail up -d
# Database operations
migrate:
./vendor/bin/sail artisan migrate
fresh:
./vendor/bin/sail artisan migrate:fresh --seed
seed:
./vendor/bin/sail artisan db:seed
backup:
./vendor/bin/sail exec mysql mysqldump -u sail -ppassword laravel > backup_$(shell date +%Y%m%d_%H%M%S).sql
# Development tools
test:
./vendor/bin/sail test
test-coverage:
./vendor/bin/sail test --coverage
analyze:
./vendor/bin/sail exec laravel.test ./vendor/bin/phpstan analyse
fix:
./vendor/bin/sail exec laravel.test ./vendor/bin/php-cs-fixer fix
# Asset compilation
dev:
./vendor/bin/sail npm run dev
build:
./vendor/bin/sail npm run build
watch:
./vendor/bin/sail npm run dev -- --watch
# Utility commands
logs:
./vendor/bin/sail logs -f
shell:
./vendor/bin/sail shell
tinker:
./vendor/bin/sail artisan tinker
queue:
./vendor/bin/sail artisan queue:work
clear:
./vendor/bin/sail artisan optimize:clear
./vendor/bin/sail artisan view:clear
./vendor/bin/sail artisan route:clear
./vendor/bin/sail artisan config:clear
Debugging and Monitoring
Container Health Monitoring
Add health checks to your services:
services:
laravel.test:
# ... other configuration
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mysql:
# ... other configuration
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "sail", "-ppassword"]
interval: 30s
timeout: 10s
retries: 3
Log Aggregation
Configure centralized logging with a custom log driver:
<?php
// config/logging.php
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single', 'docker'],
'ignore_exceptions' => false,
],
'docker' => [
'driver' => 'single',
'path' => '/dev/stdout',
'level' => env('LOG_LEVEL', 'debug'),
'formatter' => \Monolog\Formatter\JsonFormatter::class,
],
],
Security Considerations
๐ Development Security Checklist
- โข Never commit .env files with real credentials
- โข Use strong passwords even for local databases
- โข Regularly update container images
- โข Limit exposed ports to necessary services only
- โข Use secrets management for sensitive configuration
Environment Isolation
Create environment-specific configurations:
# .env.local (for local development)
APP_ENV=local
APP_DEBUG=true
DB_HOST=mysql
# .env.staging (for staging environment)
APP_ENV=staging
APP_DEBUG=false
DB_HOST=staging-mysql.internal
# .env.production (for production - never commit!)
APP_ENV=production
APP_DEBUG=false
DB_HOST=prod-mysql.internal
Troubleshooting Common Issues
Problem: Slow file operations on macOS
Solution: Use :delegated volume mounts and exclude heavy directories
- './:/var/www/html:delegated'
Problem: Port conflicts
Solution: Use different ports in .env
APP_PORT=8080
MYSQL_PORT=3307
Problem: Permission issues
Solution: Match user IDs in .env
WWWUSER=$(id -u)
WWWGROUP=$(id -g)
Conclusion
A well-configured Laravel Sail environment becomes the foundation for successful project delivery. By investing time in proper setup, you eliminate countless hours of debugging environment-specific issues and create a development experience that scales with your team.
The key is treating your development environment as seriously as production. With these configurations, you'll have a robust, performant, and maintainable development setup that mirrors production and supports your entire team's workflow.
Ready to Optimize Your Development Workflow?
These configurations have helped teams reduce setup time from days to minutes and eliminate environment-related bugs entirely. Start with the basics and gradually add the advanced features as your team grows.
Remember: A great development environment is an investment that pays dividends throughout the project lifecycle.
Need help setting up a robust development infrastructure for your team? Let's chat about creating development workflows that scale with your startup's growth.

Chris Page
Fractional CTO and Software Engineer with 25+ years of experience. I help startups scale from 0 to 7 figures using AI-assisted development and proven frameworks.