Developer Docker development environment

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 compose available (the legacy docker-compose binary also works)
  • Dev dependencies installed. The generated containers build from vendor/laravel/sail/runtimes/8.4, which ships with laravel/sail — a dev dependency of the skeleton. If you installed with composer 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:

  1. Ask which database and which additional services you want, and on which host port.
  2. Ask for the site name, domain and super admin credentials up front — before the containers exist.
  3. Write compose.yaml, docker/php.ini, .env and the database config.
  4. Generate an application key if you don't have one.
  5. Start the containers and wait for them to report healthy.
  6. 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.

Laravix Documentation · 25.08.2026
Star on GitHub