Local development environments are fragile sandcastles. Homebrew, XAMPP, and Valet are local state pollution. It's time to pave over them with concrete using Docker.

Last month, I watched a new hire spend his first three days doing nothing but fighting his local environment.
He had the wrong PHP version installed via Homebrew. His local Redis was bound to the wrong port. MySQL was throwing a cryptic socket error that stack overflow couldn't solve. Three days of engineering salary vaporized because his laptop was a chaotic snowflake of global state.
That isn't software engineering. That's digital archeology.
Local development setups—whether it's XAMPP, Homebrew, or even Laravel Valet—rely on hope. They hope your OS hasn't updated something underlying. They hope your globally installed extensions match production.
Docker paves over that hope with concrete.
When you run php artisan serve on your host machine, you aren't building a production-ready application. You are building an application that happens to tolerate the exact, chaotic state of your specific laptop on this specific Tuesday.
The moment another developer pulls your code, or you push to staging, the illusion shatters.
Docker enforces discipline. It forces you to declare every single dependency, extension, and service your app needs to survive.
Continue Reading
A docker-compose.yml isn't just a configuration file. It's an immutable contract between your team.
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- .:/var/www/html
ports:
- '8000:8000'
networks:
- laravel_network
mysql:
image: mysql:8.0
environment:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: secret
volumes:
- mysql_data:/var/lib/mysql
networks:
- laravel_network
redis:
image: redis:alpine
networks:
- laravel_network
volumes:
mysql_data:
networks:
laravel_network:
driver: bridgeWhen you commit this file, you are saying: "I don't care what OS you run, what brew packages you installed last year, or what phase the moon is in. You will run PHP 8.3, MySQL 8.0, and Redis. Period."
Your Dockerfile shouldn't be a bloated, copy-pasted mess you found in a 2018 tutorial. It needs to be intentional.
FROM php:8.3-fpm
# Install the exact system dependencies we need. Nothing more.
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Lock down our PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Get Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/htmlNotice the absence of bloat. We only install what the application explicitly requires. We don't guess. We declare.
The biggest complaint developers have about Docker (especially on macOS) is that it's "too slow."
Docker isn't slow. Your volume management is bad.
If you mount your entire project directory—including vendor/ and node_modules/—into the container, Docker has to sync tens of thousands of tiny files across the hypervisor bridge every time you make a change. It's like trying to drink an ocean through a straw.
Here is what actually works:
docker-compose down vs docker-compose down -v).vendor directory using anonymous volumes, or use Docker's VirtioFS on Mac for native-like file system performance.Stop polluting your host machine.
Need to run a migration? Don't run php artisan migrate. Run docker-compose exec app php artisan migrate.
Need to install a package? docker-compose exec app composer require guzzlehttp/guzzle.
If you can't tear down your entire development environment and spin it back up from zero in under 3 minutes, you aren't doing engineering. You're doing arts and crafts.
Is your local environment a liability, or an asset?

AI Engineer & Full-Stack Tech Lead
Expertise: 20+ years full-stack development. Specializing in architecting cognitive systems, RAG architectures, and scalable web platforms for the MENA region.
Practical AI + full-stack insights for MENA builders. No spam.