Introduction
Most Docker setups for Laravel applications are… fine.
They work locally, they run php artisan serve, and that’s about it.
But when you start building real-world Laravel & Filament applications used in production, those setups quickly become a liability:
- slow builds
- bloated images
- security issues
- poor separation between development and production
I’ve personally run into these issues multiple times before refining this setup.
👉 This article focuses on the core ideas and architecture.
The full production-ready implementation (with complete Dockerfile, edge cases and CI/CD integration) is available on Filament Mastery.
What This Article Covers
In this article, I’ll walk through the key concepts behind a Docker setup I use in production for Laravel & Filament projects.
This includes:
- multi-stage builds
- optimized dependency installation
- frontend asset compilation
- non-root execution for better security
- environment-specific configuration (dev vs production)
The Problem with “Basic Docker Setups”
A typical Dockerfile often looks like this:
FROM php:8.4-fpm
COPY . .
RUN composer install
RUN npm install
Simple… but problematic.
Main issues:
- installs dev dependencies in production
- no asset compilation strategy
- runs as root
- large and slow images
- no separation of concerns
👉 This is fine for learning, but not for production.
A Better Approach
Instead of a single container doing everything, I rely on multi-stage builds and clear separation of responsibilities.
Typical structure:
- a Composer stage to install PHP dependencies
- a Node stage to build frontend assets
- a final PHP-FPM image focused only on runtime
👉 The goal is simple: keep the runtime image as small, secure and predictable as possible.
Key Idea: Build-Time vs Runtime
One of the biggest improvements comes from moving as much work as possible to build time.
In my experience, this means:
- installing dependencies during build (not at runtime)
- compiling assets once
- shipping only the final artifacts
👉 The container becomes immutable and easier to reason about.
Example (Simplified)
Instead of a single-stage Dockerfile, the idea is to split concerns:
# Composer stage (dependencies)
RUN composer install --no-dev
# Node stage (assets)
RUN npm ci && npm run build
# Final image
COPY built assets + vendor only
👉 This is intentionally simplified, but it reflects the core idea.
Why This Matters
With this approach:
- builds are faster thanks to caching
- images are significantly smaller
- attack surface is reduced
- development and production concerns are clearly separated
In production environments, these differences quickly become critical.
Going Further
This article only covers the Docker image itself.
In a real production setup, you also need:
- a proper Docker Compose architecture
- a CI/CD pipeline to build and validate images
- deployment strategies
👉 I’m progressively documenting this production setup (Docker, Compose, CI/CD and more) here:
https://filamentmastery.com/articles/production-ready-docker-setup-for-laravel-filament/
Docker setups are often underestimated in Laravel projects.
But in my experience, investing in a clean, production-ready setup early saves a lot of time later, especially when your application starts scaling.
Top comments (0)