Docker Laravel Development Environment: Step-by-Step Setup (2026)

Set up a docker laravel development environment for fast, consistent local testing. Learn docker-compose, volumes, queue workers, and best practices.

Local PHP and Laravel installs tend to get messy fast. Differences between development environments—native PHP, different database versions, system libraries—cause weird bugs and slow onboarding. Using a docker laravel development environment eliminates 'works on my machine' problems by standardizing the stack for every developer: PHP version, database, cache, and queue are all reproducible and disposable.

In this step-by-step guide, I’ll show you how to bootstrap a clean, fast Laravel dev environment using Docker Compose. You’ll learn to troubleshoot common pitfalls, apply real-world tweaks for production parity, and optimize your Laravel workflow on Docker. Whether you’re on Windows, Mac, or Linux, this is the stack you want for a reliable local development experience in 2026.

What is a Docker Laravel Development Environment?

A docker laravel development environment is a local setup where you run your Laravel application, database (like MySQL), cache (like Redis), mail capture, and supporting services as isolated Docker containers. This approach ensures your app runs in the same environment regardless of operating system or system dependencies, reducing the dreaded "it works on my machine" syndrome and making onboarding seamless.

By declaring your infrastructure as code with Docker and docker-compose, you can define exact PHP, MySQL, and Redis versions, add extra services like Mailhog for catching outbound emails, and guarantee consistency between development, continuous integration, and production. Docker Compose allows easy orchestration of multiple services, so you can spin up or down your entire Laravel stack in seconds.

  • Consistency across development, CI, and deployment
  • Swappable PHP and database versions for testing upgrades or legacy support
  • Easy, disposable environments—tear down and start from scratch any time
  • Simple onboarding: new devs only need Docker to work productively

Prerequisites: What You Need Before Starting

Before starting with your docker laravel development environment, confirm you have the following prerequisites in place:

- Docker Desktop (recommended for Mac and Windows) or Docker Engine (for Linux) installed and running - Composer installed on your local machine for Laravel project management - Familiarity with the command line, basic Git usage, and a code editor like VS Code or PhpStorm

This guide will use Laravel 11 and PHP 8.3 in all examples, but the workflow works well with older (Laravel 9/10) or future releases. Make sure Docker has allocated at least 2GB RAM for better PHP and database container performance. Optional: Node.js locally for running npm/yarn inside or outside containers.

Step 1: Create a New Laravel Project

First, you'll need a Laravel codebase. If you already have an existing project, you can skip to setting up Docker. To start a fresh Laravel project for your docker laravel development environment, use Composer:

composer create-project laravel/laravel docker-demo

Step 2: Add a Dockerfile for Laravel

A Dockerfile defines the application container, including PHP version, extensions, Composer, and working directory. This reproducibility is crucial for any docker laravel development environment—no more 'it works for me' headaches.

Here's a robust Dockerfile for Laravel 11 with PHP 8.3 FPM and Composer. FPM is more production-ready than the built-in PHP development server. We'll later show how to run 'php artisan serve' when needed for hot-reloads.

FROM php:8.3-fpm

# System dependencies
RUN apt-get update \
    && apt-get install -y \
        libpng-dev libonig-dev libxml2-dev zip unzip git curl \
    && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Install Composer from official Composer image
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

WORKDIR /var/www

# Copy existing application code
COPY . .

RUN composer install --no-interaction --prefer-dist --optimize-autoloader

CMD ["php-fpm"]

Step 3: Set Up docker-compose for Services

docker-compose lets you describe your docker laravel development environment—application, database, cache, and supporting tools—in a single YAML file. This enables you to orchestrate the full Laravel stack with one command.

Below is a best-practice docker-compose.yml for running Laravel, MySQL, and Redis. Notice that we're exposing app and database ports for local access, binding volumes for persistent storage and hot code reload, and setting up inter-service networking so containers resolve each other's service names (e.g., 'db', 'redis') as hostnames.

version: '3.9'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: laravel-app
    container_name: laravel-app
    ports:
      - '8000:8000'
    volumes:
      - ./:/var/www
    depends_on:
      - db
      - redis
    environment:
      APP_ENV: local
      DB_CONNECTION: mysql
      DB_HOST: db
      DB_PORT: 3306
      DB_DATABASE: laravel
      DB_USERNAME: laravel
      DB_PASSWORD: secret
      CACHE_DRIVER: redis
      QUEUE_CONNECTION: redis
      REDIS_HOST: redis
  db:
    image: mysql:8.0
    container_name: laravel-db
    restart: always
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_USER: laravel
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
    ports:
      - '3306:3306'
    volumes:
      - dbdata:/var/lib/mysql
  redis:
    image: redis:alpine
    container_name: laravel-redis
    ports:
      - '6379:6379'
  mailhog:
    image: mailhog/mailhog
    container_name: laravel-mailhog
    ports:
      - '8025:8025'
volumes:
  dbdata:

How Docker Networking Works in Laravel Development

In a docker laravel development environment, each service declared in your docker-compose.yml gets its own container with an internal Docker network. They can communicate with each other using the service name as the hostname—crucial for configuring Laravel's .env. For example, set 'DB_HOST=db' and 'REDIS_HOST=redis', not 'localhost'.

If you need to connect to MySQL with a GUI (like TablePlus or DBeaver), use host '127.0.0.1' and port '3306', since we published that port in docker-compose.

How to Fix 'php artisan' Not Found in Docker

A frequent hiccup: after shelling into your app container with 'docker-compose exec app bash', running 'php artisan' fails with:

php: can't open 'artisan': No such file or directory

This almost always means your container's working directory or mounted volume isn't at your Laravel project root (where artisan is located). Double check these settings:

WORKDIR /var/www
volumes:
  - ./:/var/www

How to Run Laravel Migrations and Serve Your App in Docker

Once Docker Compose is running, you'll want to run database migrations, seeders, and launch the web server for local access. Use commands like these:

docker-compose up -d

docker-compose exec app php artisan migrate

docker-compose exec app php artisan serve --host=0.0.0.0 --port=8000

Best Practices for a Modern Docker Laravel Development Environment

Setting up your containers is only the start. Here are best practices for a fast, reliable docker laravel development environment team members will love:

  • Use named volumes, not bind mounts, for your database. This keeps DB data persistent between container rebuilds and avoids accidental data loss.
  • Pin your service image versions explicitly (e.g., 'mysql:8.0', 'php:8.3-fpm') to prevent unexpected breaking updates when Docker images change upstream.
  • Add Xdebug only in a separate debug Dockerfile or a '--build-arg' to avoid performance hits for everyone by default.
  • For front-end assets (npm/yarn), run builds in a temporary 'node:current-alpine' container, or set up a separate 'node' service. Don't pollute the PHP image with node tools.
  • Consider using Laravel Sail for onboarding and small teams, but use a custom Compose file for more production-like environments and flexibility.
  • Define php.ini and .env tweaks for local-only settings (e.g., mail, log channels, queue drivers) to avoid leaking environment-specific bugs.
  • Regularly run 'docker-compose down -v' for a full reset, but remember this wipes the named DB volume.
  • On Linux/macOS: Recursively fix permissions for the storage and bootstrap/cache directories after rebuilds: docker-compose exec app chmod -R 777 storage bootstrap/cache
  • On Windows/WSL2: Use WSL2 filepaths for the highest volume performance; avoid mapping to C:\ drive for large projects.

Laravel Sail vs Custom Docker Compose: Which is Better?

Laravel Sail is Laravel's official, zero-config docker laravel development environment for new projects. Sail delivers a ready-made docker-compose.yml and scripts, letting you get started instantly—great for new teams or quick experiments. Use 'vendor/bin/sail up' instead of 'docker-compose up'.

But Sail can become restrictive for growing teams, larger codebases, or apps that need custom PHP settings, extra services, or match your production stack. With a custom Docker Compose setup, you have full control over images, service configuration, Xdebug toggling, performance tuning, and extra tools like Mailhog, Minio, or Elasticsearch.

  • Use Sail for smaller, single-purpose projects and rapid Laravel onboarding
  • Use custom Compose for team environments, when production and dev parity matters, or when adding non-standard services

Common Errors and Troubleshooting Tips in Dockerized Laravel

Most errors in Dockerized Laravel are due to environment mismatches, permissions, or confusion about container networking. Here are solutions to the most common docker laravel development environment problems:

- SQLSTATE[HY000] [2002] Connection refused — Make sure 'DB_HOST' in your .env matches the MySQL service name in docker-compose (here, 'db'), not 'localhost' or '127.0.0.1'. - Permission denied for storage/ or bootstrap/cache — Fix recursively inside the container:

  • Can't connect to Redis? Double check your .env has 'REDIS_HOST=redis' and port 6379 is exposed in docker-compose.
  • Composer install errors: Remove vendor and composer.lock, rebuild your app container, and try running composer install again.
  • Container doesn't restart after code changes: Make sure your 'volumes' are pointing to the right folder, and use 'docker-compose restart app' when switching branches.
  • Slow file sync on Mac/Windows: Keep your code and Docker environment inside the native filesystem, not a network drive, to avoid performance bottlenecks.
docker-compose exec app chmod -R 777 storage bootstrap/cache

Bonus: Running Laravel Queue Workers in Docker

For scalable local development, never overload the web app container with background workers. Instead, add a dedicated queue worker service to your docker laravel development environment. This mirrors how you'd run multiple processes in production (e.g., on Forge or Kubernetes). Here's how you can add a 'queue' service to your docker-compose.yml:

  queue:
    build: .
    image: laravel-app
    container_name: laravel-queue
    depends_on:
      - db
      - redis
    command: php artisan queue:work
    volumes:
      - ./:/var/www

Extending Your Docker Laravel Development Environment: Mailhog, Minio, and More

Beyond the core stack, consider enhancing your local environment for full production testing parity:

- Mailhog: Catches outbound mail sent from Laravel, accessible at http://localhost:8025. Set 'MAIL_MAILER=smtp', 'MAIL_HOST=mailhog', and 'MAIL_PORT=1025' in your .env to route emails here.

- Minio: An S3-compatible object storage, great for testing file uploads and storage disks just like production S3. Add a Minio service to docker-compose, and set 'FILESYSTEM_DISK=s3', pointing S3 variables to Minio.

- Custom Nginx/Apache: For static file serving or SSL emulation. Production-like web stacks help surface issues early.

- Makefiles & Scripts: Add a Makefile or helper script to automate common tasks like up, down, exec, migrate, seed—speeding up daily workflows, especially in teams.

Conclusion: Reliable Local Laravel with Docker Makes You Faster

Setting up a reliable docker laravel development environment means onboarding is swift, local testing mimics production, and annoying dev-machine-specific bugs become rare. Docker Compose stacks make it easy to add or remove services as needed over time.

Get comfortable with adding helpers like Mailhog for email capture and Minio for S3, tweak your workflow with scripts or Makefiles, and regularly prune containers/volumes for top performance. Invest a bit in learning Docker, and you’ll reap developer velocity and cross-team consistency benefits for every Laravel project you build. Happy coding!

Frequently asked questions

Is Laravel Sail better than a custom Docker Compose setup?

Laravel Sail provides a quick, zero-config docker laravel development environment—perfect for small teams, rapid prototyping, and new Laravel developers. However, for teams that require deeper customization, environment parity with production, or need to add non-standard services, a custom Docker Compose setup offers greater flexibility, performance, and long-term maintainability. As your project grows, migrating from Sail to a custom Compose becomes a best practice.

How do I debug failed database connections when using Docker?

When using a docker laravel development environment, ensure your .env uses the docker-compose database service name for DB_HOST (usually 'db'), not 'localhost'. Also, confirm your app and db containers are both running ('docker-compose ps'). Enable verbose logging in Laravel and check container logs (`docker-compose logs db`) if problems persist. For local MySQL GUIs, connect to 127.0.0.1:3306 (or as mapped in your compose file).

Can I use Docker for Laravel development on Windows?

Yes, Docker Desktop fully supports Laravel development on Windows, though file system and volume performance can lag compared to Mac/Linux, especially when codebases live on mounted Windows (C:\) drives. For the best docker laravel development environment experience, store your Laravel code in the WSL2 Linux filesystem and run all Docker and composer/npm commands inside WSL2 when possible.

What's the best way to persist MySQL data in a Laravel Docker environment?

Use a named Docker volume for your MySQL service in docker-compose ('dbdata' in our sample). This means your database survives app container rebuilds or code changes. Avoid bind mounts or ephemeral storage unless running quick tests only. You can reset named volumes with 'docker volume rm docker-demo_dbdata' if you want to start over.

Is Xdebug supported in Docker for Laravel?

Yes, Xdebug works well inside a docker laravel development environment. Add it to your Dockerfile (e.g., RUN pecl install xdebug && docker-php-ext-enable xdebug) in a separate development build stage. Add debugging config to your php.ini and configure your IDE to listen for connections from the app container. Expose Xdebug's port (9003+), and set 'XDEBUG_CLIENT_HOST=host.docker.internal' (for Mac/Windows) or your local IP (for Linux) in php.ini or .env.