Introduction
In the previous article, I showed how to build a production-ready Docker image for Laravel & Filament.
But in real-world applications, a single container is never enough.
Running a production application means dealing with multiple concerns:
- web server
- PHP runtime
- database
- cache
- background workers
- scheduled jobs
And this is where things usually start to get messy.
The problem with "simple" setups
Most Docker Compose examples look like this:
- one container
- maybe a database
- everything else mixed together
It works.
Until it doesn’t.
From my experience, this approach quickly leads to:
- poor observability
- difficult debugging
- no real scaling strategy
- fragile deployments
A simple rule I follow
Over time, I ended up following one principle:
👉 one container = one responsibility
It sounds simple, but it completely changes how you design your architecture.
A production-oriented architecture
Instead of one container doing everything, I split responsibilities:
-
app→ PHP-FPM runtime -
web→ reverse proxy (Nginx) -
db→ PostgreSQL -
redis→ cache & queues -
horizon→ queue workers -
scheduler→ scheduled jobs
Each service is isolated.
Each service can scale independently.
Each service can fail independently.
👉 This is what makes the system predictable.
A common trap: the "public volume"
One mistake I’ve seen (and made) multiple times is how static assets are handled.
A typical setup uses:
public:/var/www/app/public
Looks fine.
But in practice:
- old assets can persist between deployments
- new builds may not be reflected
- deployments become inconsistent
👉 This kind of issue is subtle… and painful in production.
Another key point: bootstrap vs runtime
In many setups, migrations and initialization tasks run inside the main container.
I prefer separating concerns:
- runtime containers → long-running processes
- bootstrap → one-time tasks (migrations, setup)
👉 In real production systems, this is often handled in CI/CD pipelines instead.
Why this matters
This kind of architecture gives you:
- better isolation
- clearer debugging
- safer deployments
- real scalability
It’s not the simplest setup.
But it’s much closer to what you actually need in production.
Going further
In this article, I intentionally kept things focused on concepts and architecture.
👉 I cover the full Docker Compose setup (with real configuration, volumes, healthchecks, and production patterns)
https://filamentmastery.com/articles/production-ready-docker-compose-for-laravel-filament/
Series
This article is part of a series on production-ready Laravel & Filament setups:
- Docker image (multi-stage build)
- Docker Compose architecture
- CI/CD pipelines
- deployment strategies
I’ll be covering each part progressively.
If you’ve already built similar setups, I’d be curious to hear how you structure your containers in production.












