Development
Typical development workflow
- Pull the latest changes from the remote repository.
- Fetch the latest database dump from the production environment with
ahoy fetch-db. - Build the project with
ahoy build. - Start a new feature or bugfix branch:
- Create a new branch from
develop. - Implement the feature or fix the bug.
- Create a new branch from
- Run tests:
- Run automated tests locally.
- Fix any failing tests.
- Run code quality checks:
- Run static code analysis locally.
- Fix any issues reported.
- Commit changes to the branch and push it to the remote repository.
- Create a pull request:
- Create a pull request from the branch to
develop. - Assign reviewers.
- Wait for the continuous integration pipeline to pass.
- Create a pull request from the branch to
Running CLI commands
You can run CLI commands inside the project containers using ahoy command
wrapper.
# Run a command in the CLI container
ahoy cli echo "Hello, World!"
To SSH into the CLI container:
ahoy cli
You can also use shortcuts for common commands:
# Run Drush command
ahoy drush status
# Run Composer command
ahoy composer install
Switching branches
When switching to a new branch, there is no need to run ahoy build again as
it may take a long time to rebuild the entire project. Instead, you can
run these commands as needed based on what changed:
# Update Composer dependencies (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
Fetching database
To fetch the database with the latest data from the production environment,
use the ahoy fetch-db command, which will download the latest database
dump from the production environment into a .data directory.
If there was a download attempt on the same day (locally or from CI), it will download the cached database dump.
Use ahoy fetch-db --fresh to create a new database dump regardless of the cache.
The database dump is stored in the .data directory instead of being directly
imported into the local environment to allow for caching and reusing the
database dump without needing to download it every time you need to refresh
the local environment.
You can manually download the database dump from the production environment,
name it db.sql, and place it in the .data directory.
Refreshing database
Use ahoy provision to import the database dump into the local environment
and run all the necessary updates. Run this command any time you need to
reset the local environment to use the fresh database dump stored in .data.
Alternatively, you could use the ahoy import-db command (instead of
ahoy provision) to import the database dump without running any updates. This
is useful if you want to quickly reset the database without applying any updates
or changes.
You can also export timestamped database dumps from the local environment into
.data directory using the ahoy export-db command. You can then use these
dumps to restore the local environment to a specific state: rename the dump
file to .data/db.sql and run ahoy import-db.
➡️ See Drupal > Provision
Environment variable updates
To update environment variables in your local development environment:
-
Edit variables in
.env.localfile -
Apply changes by restarting containers:
ahoy restart
For more comprehensive variable reference, see Variables.
Debugging with Xdebug
To enable Xdebug for debugging browser and CLI requests:
ahoy debug # Enable Xdebug
ahoy up # Disable Xdebug
For complete Xdebug setup and IDE configuration, see Tools > Xdebug.
Working with Composer packages
Installing
To install packages, use composer require to include the package and resolve dependencies.
composer require drupal/devel
By default, stable releases are installed. If you need a non-stable version (e.g., alpha, beta, RC), specify the version constraint explicitly:
composer require drupal/devel:^1.0.0@beta
Make sure that the minimum-stability setting in composer.json is set to
the version constraint you need. For example, to allow alpha, beta, and RC versions:
{
"minimum-stability": "beta"
}
Adding JavaScript/CSS libraries (npm packages)
To install JavaScript or CSS libraries as Drupal libraries with Composer, they must be defined as inline Composer packages.
-
Define the package in
composer.jsonunder therepositoriessection:{
"repositories": [
{
"type": "package",
"package": {
"name": "gdsmith/jquery.easing",
"type": "drupal-library",
"version": "1.4.1",
"source": {
"type": "git",
"url": "https://github.com/gdsmith/jquery.easing",
"reference": "1.4.1"
}
}
}
]
} -
Require the package using Composer:
composer require gdsmith/jquery.easing
Updating
To update all dependencies:
composer update
If your project uses patches to modify dependencies, the update may fail if the patches are not compatible with the new versions of the dependencies.
A common solution is to remove the patches temporarily, run the update, and then reapply the patches one by one.
To update a specific package and its dependencies:
composer update vendor/package-name --with-dependencies
For updating Drupal core, use:
composer update "drupal/core-*" --with-dependencies
After updating core, review changes with git diff, especially modified scaffolding files like .htaccess, and commit them in a single commit.
Overriding paths
To override package installation paths, modify composer.json:
{
"extra": {
"installer-paths": {
"web/libraries/chosen": [
"npm-asset/chosen-js"
],
"web/libraries/{$name}": [
"type:drupal-library",
"type:npm-asset",
"type:bower-asset"
]
}
}
}
Patching
Vortex uses cweagans/composer-patches v2.x for applying patches to Composer dependencies. Version 2.x uses git-based patching with git apply for better cross-platform consistency.
For official documentation, visit: Composer Patches Recommended Workflows
Understanding patches.lock.json
Composer Patches v2.x automatically generates a patches.lock.json file that contains:
- Patch metadata (URLs, descriptions, target packages)
- SHA-256 checksums for patch verification
This file must be committed to version control (like composer.lock).
Benefits:
- Ensures reproducible builds across teams and CI/CD environments
- Verifies patch integrity with checksums
- Prevents "works on my machine" issues with patches
- Makes the patch state explicit and trackable
Adding a new patch
-
Define the patch in
composer.jsonunderextra.patches:"extra": {
"patches": {
"drupal/foobar": {
"Fix for issue #123": "https://www.drupal.org/files/issues/fix-123.patch"
}
}
} -
Regenerate
patches.lock.json:composer patches-relock -
Remove and reinstall patched packages:
composer patches-repatchwarningcomposer patches-repatchremoves patched dependencies fromvendor/and reinstalls them. Ensure you have no unsaved changes in those directories. -
Update
composer.lock:composer update --lock
Removing a patch
-
Delete the patch definition from
composer.json -
Regenerate
patches.lock.json:composer patches-relock -
Manually delete the affected dependency:
rm -rf vendor/drupal/foobar -
Reinstall without the patch:
composer patches-repatch -
Update
composer.lock:composer update --lock
Composer security auditing
Composer 2.9.0 introduced automatic security auditing that checks your dependencies for known security vulnerabilities and abandoned packages. This feature helps you maintain a secure codebase by alerting you to potential issues during package installation and updates.
Configuration Options
Configure audit behavior in your composer.json under the config section:
{
"config": {
"audit": {
"abandoned": "report",
"block-insecure": true,
"ignore": {
"CVE-2024-1234": "The affected component is not in use in our application.",
"GHSA-xxxx-yyyy-zzzz": "Mitigated by additional security measures."
}
}
}
}
Available Options:
block-insecure: Controls whether packages with security vulnerabilities block installationtrue(Vortex default): Blocks installation/update of vulnerable packages unless ignoredfalse: Shows warnings but allows installation to proceed
abandoned: Controls how abandoned packages are handledreport(Vortex default): Shows abandoned packages as warnings but doesn't failfail: Audit command fails with non-zero exit codeignore: Skips abandoned packages in audit reports
ignore: Ignores specific security advisories by CVE or GHSA identifier (empty by default)
When to Use block-insecure: false
Vortex sets block-insecure to true by default to enforce security best practices. However, you may want to set it to false when:
- You need flexibility to evaluate vulnerabilities on your timeline
- No secure version is immediately available
- The vulnerability doesn't affect your specific use case
- You're in active development and need uninterrupted workflow
Keep it true (Vortex default) when:
- Working on production sites with strict security requirements
- Your deployment process can handle blocked installations
- You want to enforce immediate action on security vulnerabilities
- Your team has resources to quickly address security issues
Vortex adopts a security-first approach by setting block-insecure: true as the default. This prioritizes safety in automated deployments by preventing vulnerable packages from being installed without explicit review.
If you need to override this setting for backwards compatibility, you can modify the audit.block-insecure configuration in your project's composer.json file. However, we strongly recommend addressing vulnerabilities by updating packages or using the ignore configuration for assessed exceptions, rather than routinely disabling security blocking.
This approach ensures security issues are explicitly acknowledged and reviewed before being accepted into your codebase.
Ignoring Specific Advisories
When you've assessed a vulnerability and determined it doesn't affect your project, you can ignore it:
{
"config": {
"audit": {
"ignore": {
"CVE-2024-1234": "Component is not used in our implementation.",
"GHSA-xxxx-yyyy-zzzz": "Patched via custom security fix."
}
}
}
}
Always include reasons when ignoring advisories into your Git commit messages. This helps your team understand why a vulnerability was deemed acceptable and makes it easier to review these decisions in the future.
Running Audit Command
Check your dependencies for security issues manually:
# Audit all installed packages
composer audit
# Audit only production dependencies (exclude dev)
composer audit --no-dev
# Audit packages from lock file (faster)
composer audit --locked
# Control abandoned package behavior
composer audit --abandoned=ignore # Skip abandoned packages
composer audit --abandoned=report # Show but don't fail
CI/CD Integration
Vortex automatically runs composer audit as part of the CI/CD pipeline to
check for security vulnerabilities during builds.
By default, audit failures will cause the CI build to fail. You can control this
behavior using a repository variable VORTEX_CI_COMPOSER_AUDIT_IGNORE_FAILURE
set to 1. When this variable is set to 1, the audit step will run but won't
fail the build if vulnerabilities are found.
Resetting the codebase
To reset the local environment, use the ahoy reset command. This command will
stop and remove all containers and downloaded dependency packages (vendor,
node_modules etc.).
To fully reset the repository to a state as if it was just cloned,
use the ahoy reset hard command.