Environment
Your local environment is a Docker Compose stack built from Lagoon
container images, the images
Lagoon runs in production. Ahoy wraps the longer docker compose commands
into short ones.
This section is for developers working day to day on a project built from Vortex. After reading this page, you can do the following:
- Tell which files Git, the image build and the deployment artifact leave out
- Switch branches without a full rebuild
- Reset the project to a clean state
- Change an environment variable and get the new value into the containers
In this section
Each layer of the stack has its own page in this section:
| Page | What it covers |
|---|---|
| Docker | The container stack and the docker-compose.yml anatomy |
| Pygmy | The shared proxy, DNS, SSH agent and mail catcher services |
| Ahoy | Command shortcuts, configuration and running CLI commands |
| Doctor | Stack diagnostics and system information |
| Drush | The Drupal CLI, its configuration and aliases |
| Logs | Container logs and the Drupal watchdog log |
| Debugging | Xdebug, authenticated requests and container debugging |
| Troubleshooting | Common local stack failures and fixes |
Ignored files
Vortex writes its 3 ignore files as deny lists. Every file is included by default, and each ignore file lists only what must stay out of its target. This follows the "avoid silent errors" principle: a file you add is visible by default. With an allow list, a new file would stay excluded until someone remembered to allow it.
The .gitignore file controls which paths Git ignores in the project
repository. It excludes the following:
- Directories that Composer and npm generate, such as
web/core,web/modules/contrib,vendorandnode_modules - The Drupal scaffold files that the build copies into
web/ - Compiled theme assets in
web/themes/**/build - With Storybook, the generated
*.stories.jsonfiles and thestorybook-staticoutput - Local overrides:
.env.local,.ahoy.local.yml,docker-compose.override.yml,settings.local.phpandservices.local.yml - Content files and test artifacts in
web/sites/*/filesandweb/sites/simpletest - Caches, data, logs and temporary artifacts in
.artifacts,.data,.logs,.phpunit.cacheand.twig-cs-fixer.cache
.gitignore keeps 2 sections as small allow lists, because a deny rule
can't express them:
recipes/- Composer installs contributed recipes next to your custom ones, so each custom recipe is un-ignored explicitly..claude/- Claude writes machine-local state here, so only.claude/settings.jsonand.claude/skills/are un-ignored by default. This section is present when the installer adds the AI agent instructions.
The other 2 ignore files apply the same deny-list model to different targets:
.dockerignorecontrols the container image build context. ➡️ See Build context and.dockerignore.gitignore.artifactcontrols the deployment artifact. ➡️ See Deployment > Artifact
A new file or directory that no entry matches is included in all 3 targets. Git tracks it after you commit it. Add an entry to an ignore file only when a file must stay out of that target.
Switch branches
After you switch branches, skip the full rebuild. Run only the commands that match what changed:
- Ahoy
- Docker Compose
# Update Composer packages (only if composer.json/composer.lock changed)
ahoy composer install
# Rebuild frontend assets (only if theme files changed)
ahoy fe
# Provision site (only if database or configuration changes expected)
ahoy provision
# Update Composer packages (only if composer.json/composer.lock changed)
docker compose exec cli composer install
# Rebuild frontend assets (only if theme files changed)
docker compose exec cli bash -c \
"cd \${WEBROOT}/themes/custom/\${DRUPAL_THEME} && npm run build"
# Provision site (only if database or configuration changes expected)
docker compose exec cli ./vendor/bin/vortex-provision
If the branch changes docker-compose.yml or a file in .docker/, rebuild
the images and recreate the containers with ahoy up --build, or
docker compose up -d --build without Ahoy.
Confirm that the stack is healthy: ahoy doctor ends with
[ OK ] All required checks have passed.
Reset the project
ahoy reset takes the stack down and deletes what the build installed, so
your next ahoy build starts clean. After you confirm, it runs ahoy down,
which removes the containers and their volumes, your local database
included. ahoy reset then deletes the following:
vendor- Every
node_modulesdirectory web/core- The
contribdirectories inweb/modules,web/profilesandweb/themes
ahoy reset --hard also returns the repository to a freshly cloned state
at the current commit. After the soft reset, it runs these steps:
- Deletes every file that
.gitignorematches. - Discards uncommitted changes to tracked files (
git reset --hard). - Removes every other untracked file (
git clean -f -d). - Removes empty directories.
The hard reset deletes your .env.local, the database dumps in .data and
every other local override, so copy out anything you want to keep first.
The following commands run each kind of reset:
- Ahoy
- Docker Compose
# Reset local environment
ahoy reset
# Fully reset repository to a state as if it was just cloned
ahoy reset --hard
# Reset local environment
docker compose down --remove-orphans --volumes
./vendor/bin/vortex-reset
# Fully reset repository to a state as if it was just cloned
docker compose down --remove-orphans --volumes
./vendor/bin/vortex-reset --hard
Confirm that the reset finished: the last line it prints is
[ OK ] Finished reset.
Environment variables
.env holds the values for the whole team, and .env.local holds the
values for your machine only. A value in .env.local overrides the one in
.env. A variable exported in your shell overrides both.
To change a variable that docker-compose.yml passes to the containers,
such as DRUPAL_THEME:
- Set the new value in
.env.localor in.env. - Recreate the containers (a plain restart keeps the old value):
- Ahoy
- Docker Compose
ahoy up
docker compose up -d
ahoy up loads both files before it calls Docker Compose. Docker Compose on
its own reads only .env, so the Docker Compose command applies only
.env changes. To include .env.local without Ahoy, pass both files:
docker compose --env-file .env --env-file .env.local up -d.
Confirm that a container has the new value with
docker compose exec cli printenv VARIABLE_NAME, where VARIABLE_NAME is
the name of the variable you changed.
Drupal also reads variables that docker-compose.yml doesn't pass, such as
DRUPAL_CLAMAV_ENABLED. For web requests, PHP-FPM loads them from .env
when its container starts and never reads .env.local. To apply a change
to .env, run ahoy restart or docker compose restart. A change to
these variables leaves the container's configuration as it was, so ahoy up
keeps the container running.
To set such a variable on your machine only, such as a credential that
must stay out of the committed .env:
-
Pass the variable to the
phpservice indocker-compose.override.yml:docker-compose.override.ymlservices:php:environment:DRUPAL_EXAMPLE_API_KEY: ${DRUPAL_EXAMPLE_API_KEY:-} -
Set its value in
.env.local. -
Run
ahoy up.
A variable that only the vendor/bin/vortex-* scripts use, such as
VORTEX_PROVISION_OVERRIDE_DB, takes effect without recreating anything,
because the scripts read both files each time they start. The
Docker page explains how
each value reaches a container.
➡️ See Variables for the full variable reference.