Docker development environment
Laravix can generate its own Docker environment: a compose.yaml, the config files it needs and a matching .env. One command gets you a database, search, mail catcher, queue worker and scheduler without installing any of them on your machine.
This is a local development tool. It is not a production deployment story — for that see Deployment.
Requirements
- Docker, with
docker composeavailable (the legacydocker-composebinary also works) - Dev dependencies installed. The generated containers build from
vendor/laravel/sail/runtimes/8.4, which ships withlaravel/sail— a dev dependency of the skeleton. If you installed withcomposer install --no-dev, that path won't exist.
Installing straight into containers
The fastest path is to let the installer do everything:
composer create-project laravix/laravix my-site
cd my-site
php artisan laravix:install
The first question the installer asks is how you want to run Laravix. Pick Docker and it will:
- Ask which database and which additional services you want, and on which host port.
- Ask for the site name, domain and super admin credentials up front — before the containers exist.
- Write
compose.yaml,docker/php.ini,.envand the database config. - Generate an application key if you don't have one.
- Start the containers and wait for them to report healthy.
- Run the rest of the installation inside the container and print the usual summary box.
Answering the questions before the containers start means the whole thing runs unattended once it gets going.
You can skip the question and go straight there with php artisan laravix:install --docker.
Generating the environment without installing
If you only want the files — to inspect them, edit them, or install later:
php artisan laravix:docker
It asks the same environment questions, writes the files and stops. Nothing is started, no containers are built.
What you get asked
Database — one of:
| Choice | Container | Notes |
|---|---|---|
mysql |
mysql:8.4 |
Default. Also writes docker/mysql/custom.cnf |
pgsql |
postgres:17 |
|
sqlite |
none | A file at database/database.sqlite, no database container at all |
Additional services — a multi-select, so pick any combination:
| Service | Container | What it gives you |
|---|---|---|
| Meilisearch | getmeili/meilisearch:latest |
Full-text search. Sets SCOUT_DRIVER=meilisearch |
| Mailpit | axllent/mailpit:latest |
Catches outgoing mail, dashboard on port 8025 |
| Redis | redis:alpine |
Sets CACHE_STORE=redis and SESSION_DRIVER=redis |
| Queue worker | app image | Runs queue:work --tries=3 --max-time=3600. Generates image variants |
| Scheduler | app image | Runs schedule:work. Publishes scheduled content every minute |
The worker and scheduler are selected by default — they are what makes image variants and scheduled publishing work without you remembering to start anything. Leave them out with --no-worker and --no-scheduler.
Host port — the port the site is served on, 80 by default.
Ports are moved out of the way
Before writing anything, the command checks whether each port it wants is actually free, and walks upward until it finds one that is. This covers the site port, the Vite port and every forwarded service port (database, Meilisearch, Mailpit, Redis).
When it moves something, it tells you:
Ports already in use, moved: site 80 → 81, db 3306 → 3307.
So Laravix can run alongside your other projects without you untangling port collisions by hand. The resolved values are written into .env as APP_PORT, VITE_PORT and the FORWARD_*_PORT variables.
Port probing only happens when there's no compose.yaml yet. Regenerating an existing environment keeps the ports you already have.
Flags
Every question has a flag, so the whole thing scripts:
php artisan laravix:docker --db=pgsql --search --mail --redis --port=8080
| Flag | Effect |
|---|---|
--db= |
mysql, pgsql or sqlite |
--search |
Add Meilisearch |
--mail |
Add Mailpit |
--redis |
Add Redis |
--no-worker |
Leave out the queue worker |
--no-scheduler |
Leave out the scheduler |
--port= |
Host port for the site |
--force |
Overwrite an existing compose.yaml |
The same flags work on laravix:install alongside --docker.
What lands on disk
| File | Contents |
|---|---|
compose.yaml |
The app service plus every service you selected, a sail bridge network, named volumes and depends_on conditions |
docker/php.ini |
PHP overrides, mounted into both the CLI and FPM config directories |
docker/mysql/custom.cnf |
MySQL only |
database/database.sqlite |
SQLite only — created empty if missing |
.env |
Connection details, ports and driver settings for what you chose |
Services that need persistence get a named volume (laravix-mysql, laravix-redis, …). Mailpit, the worker and the scheduler don't get one — nothing of theirs is worth keeping.
The app service waits for its dependencies through depends_on, using service_healthy for anything with a healthcheck and service_started for the rest.
Your existing .env is backed up
Writing .env copies the current one to .env.backup first, and only the keys Laravix manages are rewritten — the rest of your file is left alone. The command names the backup in its output when it makes one.
Regenerating
laravix:docker refuses to run when a compose.yaml already exists, so it can never quietly overwrite an environment you have tuned:
compose.yaml already exists. Rerun with --force to regenerate it.
With --force it reads your current compose.yaml first and uses what it finds there as the defaults for the questions — the database and services you already have come back pre-selected, and your existing APP_PORT and VITE_PORT are kept. Adding a service to an environment is therefore just:
php artisan laravix:docker --force --redis
Hand-written edits inside the file are not preserved. Only the set of services and the ports survive.
Running commands in the containers
If vendor/bin/sail is present, use it:
./vendor/bin/sail artisan migrate
./vendor/bin/sail artisan laravix:user --super
Otherwise go through compose directly:
docker compose exec laravel.test php artisan migrate
Both reach the same laravel.test container, which is the app service defined in compose.yaml.
Troubleshooting
"Missing stubs: services/x." You asked for a service Laravix has no template for. The supported set is MySQL, PostgreSQL, Meilisearch, Mailpit, Redis, the worker and the scheduler.
"Containers did not become healthy within 180s." The installer gave up waiting. The containers may still be coming up — check docker compose ps, and once they're healthy finish the job by hand with ./vendor/bin/sail artisan laravix:install (or the docker compose exec form).
The site is on a different port than you asked for. A port was taken and Laravix moved it. Check the warning in the output, or APP_PORT in .env.
Build fails on vendor/laravel/sail/runtimes/8.4. Dev dependencies aren't installed. Run composer install without --no-dev.
Related articles
- Installation
- CLI Commands —
laravix:dockerflag reference - Deployment — production, which this is not
- Full-text Search — configuring the Meilisearch container