Home PHP Laravel Sail: Docker Development Environment Setup Guide
Intermediate 4 min · July 13, 2026

Laravel Sail: Docker Development Environment Setup Guide

Learn Laravel Sail for Docker-based PHP development.

N
Naren Founder & Principal Engineer

20+ years shipping production PHP systems at scale. Lessons pulled from things that broke in production.

Follow
Production
production tested
July 13, 2026
last updated
2,073
articles · all by Naren
Before you start⏱ 15-20 min read
  • Basic knowledge of Laravel and PHP
  • Docker and Docker Compose installed on your machine
  • Composer installed globally or in your project
  • Familiarity with command-line interface
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Laravel Sail is a lightweight command-line interface for interacting with Laravel's default Docker configuration.
  • It provides a pre-configured Docker environment for PHP, MySQL, Redis, and more.
  • No need to install PHP, Composer, or a database locally; everything runs in containers.
  • Sail is ideal for team consistency and quick project setup.
  • It uses Docker Compose under the hood and is highly customizable.
✦ Definition~90s read
What is Laravel Sail?

Laravel Sail is a lightweight command-line interface that provides a pre-configured Docker development environment for Laravel applications, allowing you to run PHP, databases, and other services without local installation.

Imagine you're building a model ship.
Plain-English First

Imagine you're building a model ship. Instead of gathering all the tiny pieces and tools yourself, you get a complete kit with everything pre-sorted and instructions. Laravel Sail is like that kit for your web app—it gives you a ready-to-use environment (PHP, database, etc.) inside a box (Docker), so you can start building without worrying about setup.

Setting up a local development environment for Laravel can be a pain. You need PHP, Composer, a database server, Redis, maybe Node.js, and you have to manage versions and configurations. If you're working on a team, everyone's environment might be slightly different, leading to the dreaded 'it works on my machine' problem.

Enter Laravel Sail. Sail is a lightweight command-line interface for interacting with Laravel's default Docker configuration. It provides a complete development environment with PHP, MySQL, Redis, Mailhog, and more, all running in Docker containers. With Sail, you can start a new Laravel project with a single command, and your entire team gets the same environment.

Sail is built on top of Docker Compose, so you can customize it to your needs. It's perfect for both beginners who want to avoid system configuration headaches and experienced developers who need a consistent, reproducible environment.

In this tutorial, you'll learn how to install and use Laravel Sail, customize services, run commands, debug issues, and follow best practices for production-like setups. By the end, you'll be able to spin up a full Laravel environment in minutes.

What is Laravel Sail?

Laravel Sail is a lightweight command-line interface for interacting with Laravel's default Docker configuration. It provides a pre-configured Docker environment for developing Laravel applications. Sail is built on top of Docker Compose, and it's designed to be a simple, fast way to get a Laravel development environment up and running.

Sail includes services like PHP, MySQL, Redis, Mailhog, and more. You can customize which services are installed during setup. Sail also provides a convenient CLI for running common commands like 'sail artisan', 'sail composer', and 'sail npm'.

One of the key benefits of Sail is consistency. Every developer on your team gets the same environment, eliminating 'it works on my machine' issues. It also isolates your project from your host system, so you can work on multiple projects with different requirements without conflicts.

Sail is not meant for production use. It's a development tool. For production, you should use a more robust setup like Laravel Forge or custom Docker configurations.

install-sail.shPHP
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
# Install Sail in an existing Laravel project
composer require laravel/sail --dev

# Publish Sail's docker-compose.yml
php artisan sail:install

# Start Sail (runs in background)
./vendor/bin/sail up -d

# Or use the alias after installation
sail up -d
Output
Sail installation successful. Docker containers are starting.
💡Quick Start with New Projects
📊 Production Insight
Never use Sail in production. It's optimized for development and lacks security hardening.
🎯 Key Takeaway
Sail provides a consistent, containerized development environment for Laravel, eliminating local setup hassles.

Installing and Configuring Laravel Sail

To install Sail in an existing Laravel project, you need to require the package via Composer. Then run the 'sail:install' Artisan command to publish the Docker Compose file and configure services.

During installation, you can choose which services you need: MySQL, PostgreSQL, Redis, Mailhog, etc. Sail will generate a 'docker-compose.yml' file in your project root.

After installation, you can start Sail with './vendor/bin/sail up -d' or by using the 'sail' alias. To make things easier, add an alias to your shell: alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'.

Sail uses environment variables from your .env file. Make sure to set DB_HOST to 'mysql' (or the service name) instead of '127.0.0.1'. Also, set DB_PORT to 3306 (internal port).

You can customize the Docker configuration by editing the 'docker-compose.yml' file. For example, you can change the PHP version, add new services, or modify resource limits.

docker-compose.ymlPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.3
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.3/app
        ports:
            - '${APP_PORT:-80}:80'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
            - redis
    mysql:
        image: 'mysql:8.0'
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
        volumes:
            - 'sail-mysql:/var/lib/mysql'
        networks:
            - sail
    redis:
        image: 'redis:alpine'
        ports:
            - '${FORWARD_REDIS_PORT:-6379}:6379'
        volumes:
            - 'sail-redis:/data'
        networks:
            - sail
networks:
    sail:
        driver: bridge
volumes:
    sail-mysql:
        driver: local
    sail-redis:
        driver: local
🔥Customizing Sail Services
📊 Production Insight
Always version control your docker-compose.yml and .env files (except sensitive values) to ensure team consistency.
🎯 Key Takeaway
Sail installation is straightforward via Composer and Artisan. Customize services in docker-compose.yml.

Running Common Commands with Sail

Sail provides a convenient CLI for running common Laravel and PHP commands. Instead of typing 'php artisan', you use 'sail artisan'. Similarly, 'sail composer', 'sail npm', 'sail yarn', and 'sail shell' are available.

Here are some common commands
  • sail up -d: Start containers in the background
  • sail down: Stop containers
  • sail build: Rebuild containers
  • sail artisan migrate: Run migrations
  • sail composer require package: Install a Composer package
  • sail npm install: Install Node dependencies
  • sail shell: Open a bash shell inside the container
  • sail root-shell: Open a shell as root
  • sail logs: View logs from all containers
  • sail logs mysql: View logs from the MySQL container

You can also run any command inside the container using 'sail exec'.

sail-commands.shPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Start Sail in background
sail up -d

# Run migrations
sail artisan migrate

# Install a package
sail composer require laravel/sanctum

# Run tests
sail artisan test

# Open a shell
sail shell

# View logs
sail logs -f

# Stop all containers
sail down
Output
Migration successful. Sanctum installed. Tests passed.
💡Alias for Convenience
📊 Production Insight
Use 'sail artisan config:cache' in production-like environments to improve performance, but avoid it during development.
🎯 Key Takeaway
Sail wraps common commands, making it easy to run Artisan, Composer, npm, and shell commands inside the container.

Customizing Sail Services and Environment

Sail is highly customizable. You can change PHP versions, add services like Meilisearch or Selenium, and modify environment variables.

To change the PHP version, edit the 'build' context in docker-compose.yml to point to a different runtime directory (e.g., './vendor/laravel/sail/runtimes/8.2').

To add a new service, simply add a new service definition to docker-compose.yml. For example, to add Meilisearch:

meilisearch: image: 'getmeili/meilisearch:latest' ports: - '7700:7700' environment: MEILI_MASTER_KEY: '${MEILI_MASTER_KEY}' volumes: - 'sail-meilisearch:/meili_data' networks: - sail

You can also customize environment variables in the .env file. Sail uses variables like APP_PORT, DB_PORT, FORWARD_DB_PORT, etc.

If you need to install additional PHP extensions, you can create a custom Dockerfile that extends Sail's base image.

Dockerfile.customPHP
1
2
3
4
5
6
7
8
9
10
FROM sail-8.3/app

RUN apt-get update && apt-get install -y \
    libzip-dev \
    zip \
    && docker-php-ext-install zip

COPY . /var/www/html

EXPOSE 80
⚠ Custom Dockerfile Overwrites
📊 Production Insight
For production, use a dedicated Docker setup with multi-stage builds and security best practices. Sail is for development only.
🎯 Key Takeaway
You can customize Sail's services, PHP version, and environment variables to fit your project needs.

Debugging with Xdebug in Sail

Sail comes with Xdebug pre-installed, but it's disabled by default. To enable Xdebug, set the SAIL_XDEBUG_MODE environment variable in your .env file.

For example, to enable debugging and profiling: SAIL_XDEBUG_MODE=debug,profile

You also need to set the client host. On macOS and Windows, use 'host.docker.internal'. On Linux, you may need to use your host's IP address.

After setting the variables, rebuild the containers with 'sail build --no-cache' and restart.

Then configure your IDE to listen for Xdebug connections. For PhpStorm, set the server name to 'sail' and map the project root to '/var/www/html'.

You can also use 'sail debug' command to start a debugging session.

.env.xdebugPHP
1
2
3
SAIL_XDEBUG_MODE=debug,profile
SAIL_XDEBUG_CONFIG="client_host=host.docker.internal"
# For Linux, use your host IP: client_host=192.168.1.100
💡Xdebug Performance
📊 Production Insight
Never enable Xdebug in production. It exposes sensitive information and degrades performance.
🎯 Key Takeaway
Xdebug is available in Sail but disabled by default. Enable it via environment variables and configure your IDE for step debugging.

Sharing Your Local Site with Sail Share

Sail includes a 'share' command that exposes your local development site to the internet using Ngrok. This is useful for testing webhooks, mobile apps, or sharing progress with clients.

To use it, simply run: sail share

This will start an Ngrok tunnel and provide a public URL like https://abc123.ngrok.io.

You can customize the subdomain or region using options: sail share --subdomain=myapp --region=eu

Note: Ngrok requires an account for custom subdomains and longer sessions. You can sign up for free at ngrok.com.

sail-share.shPHP
1
2
3
4
5
6
7
8
# Share your site with a random URL
sail share

# Share with a custom subdomain (requires Ngrok account)
sail share --subdomain=myapp

# Specify region
sail share --region=eu
Output
Laravel Sail is sharing your application...
Public URL: https://abc123.ngrok.io
🔥Ngrok Limitations
📊 Production Insight
Never use Ngrok tunnels for production traffic. They are for development testing only.
🎯 Key Takeaway
Sail share uses Ngrok to expose your local site publicly, ideal for testing external services.

Sail Best Practices and Common Pitfalls

Here are some best practices to get the most out of Laravel Sail:

  1. Use .env for configuration: Keep environment-specific settings in .env. Never commit sensitive data to version control.
  2. Rebuild containers after changes: If you modify docker-compose.yml or Dockerfile, run 'sail build --no-cache' to apply changes.
  3. Persist data with volumes: Sail uses named volumes for databases and Redis. This ensures data persists across container restarts.
  4. Avoid using 'sail down' unnecessarily: It stops and removes containers. Use 'sail stop' to pause them.
  5. Set file permissions: If you encounter permission issues, run 'sail root-shell' and fix permissions inside the container.
  6. Use 'sail artisan optimize' for production: Before deploying, run optimization commands like 'config:cache', 'route:cache', etc.
Common pitfalls
  • Forgetting to set DB_HOST to the service name.
  • Using 'localhost' instead of 'mysql' for database connections.
  • Not running 'sail artisan config:clear' after changing .env.
  • Assuming Sail is suitable for production.
  • Ignoring Docker resource limits (CPU, memory).
sail-best-practices.shPHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Rebuild containers after changes
sail build --no-cache

# Stop containers without removing them
sail stop

# Fix permissions
sail root-shell
chmod -R 777 /var/www/html/storage

# Clear config cache after .env changes
sail artisan config:clear

# Optimize for production-like testing
sail artisan config:cache
sail artisan route:cache
sail artisan view:cache
Output
Containers rebuilt. Permissions fixed. Cache cleared.
⚠ Resource Allocation
📊 Production Insight
Always run 'sail artisan config:clear' after changing .env to ensure the application reads the new values.
🎯 Key Takeaway
Follow best practices like using .env, rebuilding after changes, and persisting data with volumes to avoid common pitfalls.
● Production incidentPOST-MORTEMseverity: high

The Case of the Missing MySQL Connection

Symptom
Laravel throws 'SQLSTATE[HY000] [2002] Connection refused' when trying to access the database.
Assumption
The developer assumed the default .env settings were correct and that MySQL was running.
Root cause
The .env file had DB_HOST=127.0.0.1 instead of DB_HOST=mysql (the service name in docker-compose.yml).
Fix
Changed DB_HOST to 'mysql' and ran 'sail artisan config:clear'.
Key lesson
  • Always use Docker service names as hostnames when connecting between containers.
  • Run 'sail artisan config:clear' after changing .env values.
  • Check container logs with 'sail logs mysql' to verify the database is ready.
  • Use 'sail ps' to see which containers are running.
  • Remember that Sail's environment is isolated; localhost refers to the container, not your host machine.
Production debug guideSymptom to Action5 entries
Symptom · 01
Cannot run 'sail' command: command not found
Fix
Ensure you are in a Laravel project with Sail installed. Run 'composer require laravel/sail --dev' if missing.
Symptom · 02
Docker containers not starting or exiting immediately
Fix
Check Docker is running. Run 'sail build --no-cache' to rebuild images. Check logs with 'sail logs'.
Symptom · 03
Database connection refused
Fix
Verify DB_HOST in .env is set to 'mysql' (or the service name). Run 'sail artisan config:clear'.
Symptom · 04
Port conflicts (e.g., port 80 already in use)
Fix
Edit docker-compose.yml to change the host port mapping (e.g., '80:80' to '8080:80').
Symptom · 05
Slow performance on macOS/Windows
Fix
Enable Docker's file sharing optimization. For macOS, use 'sail share' for testing. Consider using WSL2 on Windows.
★ Quick Debug Cheat SheetCommon Sail issues and immediate fixes.
Sail command not found
Immediate action
Install Sail: composer require laravel/sail --dev
Commands
php artisan sail:install
sail up -d
Fix now
Add alias: alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
MySQL connection refused+
Immediate action
Check DB_HOST in .env
Commands
sail artisan config:clear
sail logs mysql
Fix now
Set DB_HOST=mysql
Port already in use+
Immediate action
Change host port in docker-compose.yml
Commands
sail down
sail up -d
Fix now
Edit ports: '8080:80'
Permission denied for storage+
Immediate action
Fix permissions inside container
Commands
sail root-shell
chmod -R 777 /var/www/html/storage
Fix now
Run 'sail artisan storage:link' after fixing
FeatureLaravel SailManual Docker SetupHomestead (Vagrant)
Setup timeMinutesHoursMinutes
Pre-configured servicesYesNoYes
CustomizabilityHighVery HighMedium
PerformanceGoodExcellentModerate
Cross-platformYes (Docker)YesLimited
Production readyNoYesNo
Learning curveLowHighMedium
⚙ Quick Reference
7 commands from this guide
FileCommand / CodePurpose
install-sail.shcomposer require laravel/sail --devWhat is Laravel Sail?
docker-compose.ymlversion: '3'Installing and Configuring Laravel Sail
sail-commands.shsail up -dRunning Common Commands with Sail
Dockerfile.customFROM sail-8.3/appCustomizing Sail Services and Environment
.env.xdebugSAIL_XDEBUG_MODE=debug,profileDebugging with Xdebug in Sail
sail-share.shsail shareSharing Your Local Site with Sail Share
sail-best-practices.shsail build --no-cacheSail Best Practices and Common Pitfalls

Key takeaways

1
Laravel Sail provides a consistent, containerized development environment using Docker, eliminating local setup issues.
2
Install Sail via Composer and customize services in docker-compose.yml to fit your project needs.
3
Use 'sail' as a prefix for Artisan, Composer, npm, and shell commands to run them inside the container.
4
Enable Xdebug for step debugging by setting environment variables and configuring your IDE.
5
Follow best practices
use service names for hostnames, clear config cache after .env changes, and avoid using Sail in production.

Common mistakes to avoid

4 patterns
×

Using '127.0.0.1' as DB_HOST in .env

×

Forgetting to run 'sail artisan config:clear' after changing .env

×

Running 'sail down' frequently

×

Assuming Sail is suitable for production

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is Laravel Sail and what problem does it solve?
Q02SENIOR
How do you enable Xdebug in Laravel Sail?
Q03SENIOR
Explain how to customize Laravel Sail to use PostgreSQL instead of MySQL...
Q01 of 03JUNIOR

What is Laravel Sail and what problem does it solve?

ANSWER
Laravel Sail is a lightweight CLI for interacting with Laravel's default Docker configuration. It solves the problem of setting up a consistent development environment by providing pre-configured containers for PHP, MySQL, Redis, etc., eliminating 'it works on my machine' issues.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Do I need to install Docker before using Sail?
02
Can I use Sail with an existing Laravel project?
03
How do I change the PHP version in Sail?
04
Why is my database connection failing?
05
Can I use Sail for production?
N
Naren Founder & Principal Engineer

20+ years shipping production PHP systems at scale. Lessons pulled from things that broke in production.

Follow
Verified
production tested
July 13, 2026
last updated
2,073
articles · all by Naren
🔥

That's Laravel. Mark it forged?

4 min read · try the examples if you haven't

Previous
Laravel Breeze and Starter Kits
23 / 24 · Laravel
Next
Livewire 3: Dynamic UIs Without JavaScript