Skip to main content

Architecture

Vortex is a production-ready Drupal project template designed to simplify onboarding, standardize processes, and ensure long-term maintainability.

This page provides a high-level overview of how the template is structured, how its components work together, and how your project benefits from its architecture.

Design principles

Vortex is guided by principles that prioritize simplicity, visibility, and maintainability:

  • Simple is better than complex: The template encourages clarity, even in customizations.
  • Use standard tools: Wherever possible, Vortex follows upstream conventions and avoids reinvention.
  • Avoid silent errors: Misconfigurations should fail loudly.
  • Readability counts: Code and configuration are meant to be understood.
  • Explicit logging helps: Scripts log every major step, so it's easy to follow what's going on.

Code lifecycle

Vortex standardizes the code lifecycle across local, CI, and hosting environments. This ensures that the same steps are followed everywhere, reducing the chance of errors and making processes predictable.

The lifecycle below is the map of the whole system - every section of this page describes one of its stages:

Local Development
═════════════════════════════════════════════════════════════════════════════════════════
Developer writes code ──► Build and test locally ──► Commit changes


Git Repository
═════════════════════════════════════════════════════════════════════════════════════════
Push to remote branch ──► Open/Update Pull Request


┌─ CI Pipeline ────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌─ Database Job (Nightly) ───────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Scheduled ──► Download production ──► Sanitize database ──► Store database cache │ │
│ │ trigger database Remove sensitive data │ │
│ │ │ │
│ └─────────────────────────────────────┬──────────────────────────────────────────────┘ │
│ │ Provides cached database │
│ ▼ │
│ ┌─ Lint Job ────────────┐ ┌─ Database Job ────────────────┐ ┌─ Audit Job ──────────┐ │
│ │ │ │ ◆ Nightly cache exists? │ │ Composer audit │ │
│ │ Build CLI container │ │ Yes ──► job succeeds │ │ (advisories) │ │
│ │ ▼ │ │ No ──► download, sanitize, │ │ ▼ │ │
│ │ Composer validate │ │ store cache │ │ Gitleaks │ │
│ │ ▼ │ └───────────────┬───────────────┘ │ (committed secrets) │ │
│ │ Composer normalize │ ▼ │ │ │
│ │ ▼ │ ┌─ Build Job ───────────────────┐ │ │ │
│ │ Hadolint │ │ Code assembly │ │ │ │
│ │ ▼ │ │ Docker, Composer deps, │ │ │ │
│ │ DCLint │ │ NPM deps, assets │ │ │ │
│ │ ▼ │ │ ▼ │ │ │ │
│ │ PHPCS │ │ Website setup │ │ │ │
│ │ ▼ │ │ Import cached DB, drush │ │ │ │
│ │ PHPStan │ │ deploy, custom scripts │ │ │ │
│ │ ▼ │ │ ▼ │ │ │ │
│ │ Rector │ │ Testing │ │ │ │
│ │ ▼ │ │ PHPUnit tests ──► Behat tests │ │ │ │
│ │ Twig CS Fixer │ └───────────────┬───────────────┘ │ │ │
│ │ ▼ │ │ │ │ │
│ │ Gherkin Lint │ │ │ │ │
│ │ ▼ │ │ │ │ │
│ │ ESLint / Stylelint │ │ │ │ │
│ │ │ │ │ │ │
│ └──────────┬────────────┘ │ │ │ │
│ │ │ │ │ │
│ ▼ ▼ │ │ │
│ ┌─ Deployment Job ─────────────────────────────────────────┐ │ │ │
│ │ │ │ │ │
│ │ Webhook Artifact Lagoon │ │ Does not gate │ │
│ │ Call URL Package artifact Run Lagoon CLI deploy │ │ deployment │ │
│ │ │ │ │ │
│ └──────────────────────────────────────────────────────────┘ └──────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────┘


Hosting Platform
═════════════════════════════════════════════════════════════════════════════════════════
◆ Environment ──No──► Sync DB from production ───┐
exists? │
│ Yes ▼
└──────────────────────────────────► drush deploy ──► Custom scripts ──► Notifications


Available Environments
═════════════════════════════════════════════════════════════════════════════════════════
┊ PR Environment ┊ Dev Staging Production
┊ (auto-removed) ┊ develop branch main branch production branch or tag

Local development environment

Your project includes a containerized local environment using Docker Compose and production-grade Lagoon images. This ensures consistency between local, CI, and hosting environments.

To simplify command usage, we use Ahoy as a wrapper. It lets you run complex tasks like provisioning, testing, or database imports with short, easy-to-remember commands.

Planned features

Support for DDEV and Lando is on our roadmap for local development environments.

➡️ See Development > Environment

Automation scripts

Vortex uses POSIX-compliant Bash scripts shipped via the drevops/vortex-tooling Composer package (installed to vendor/drevops/vortex-tooling/src/) to automate common tasks and connect components together.

These scripts:

  • Run identically across local, CI, and hosting
  • Support environment variables to adapt behavior
  • Are modular and easy to extend

The scripts are not part of the template's own files: they are a dependency. Your project's composer.json requires drevops/vortex-tooling with a tilde constraint (~1.4.0 in the shipped template), which accepts patch releases but holds the minor version, so a new minor release cannot reach your deployments until you raise the constraint yourself. Once installed, every script is available as a Composer binary at vendor/bin/vortex-<script> - for example vendor/bin/vortex-provision or vendor/bin/vortex-deploy - and the Ahoy commands wrap those binaries.

The package repository on GitHub is a read-only mirror of the .vortex/tooling/ directory of the Vortex repository. Bugs and changes go to the Vortex issue queue, not to the mirror.

Never edit the files under vendor/drevops/vortex-tooling/src/ - the next composer update discards the change. Adapt behavior through environment variables, add project logic as your own scripts under scripts/ (the provision script discovers and runs scripts/provision-*.sh), and reach for a cweagans/composer-patches patch only when a shipped script itself must change.

➡️ See Development > Composer > Vortex tooling package for updating the package and Development > Provision > Running custom scripts for extending provisioning.

Customizing scripts

All scripts support configuration via environment variables, so they can be adapted to specific project or environment needs.

During initial project setup, .env file is updated with project-specific values like project name, email etc. Then, environment variables (secrets, tokens, etc.) are set in CI or hosting environments.

➡️ See Development > Variables

Router scripts

Most Vortex commands are implemented as router script entry points, like vortex-fetch-db or vortex-deploy, that dynamically invoke the more specific logic for your setup, based on configuration or environment variables.

For example:

  • vortex-fetch-db is a router script that fetches a database from any supported hosting provider or custom location without needing to know the specifics of each provider.
  • vortex-deploy is a router script that deploys code to any hosting provider in a consistent manner, regardless of whether it's Acquia, Lagoon, or another platform.
Script architecture diagram
Diagram of scriptsDiagram of scripts

Drupal management

Provisioning

The provisioning process is central to how Vortex works. Instead of manually running Drush commands, you run a single provision script. This script handles:

  • Importing a database or initializing a database by installing Drupal from a profile
  • Running updates, config imports, cache rebuilds, and deploy hooks
  • Executing post-provision custom scripts

Because provisioning is centralized, it runs the same way in every environment: local, CI, or hosting. This eliminates "works on my machine" problems and makes the process predictable for everyone.

It also makes it possible to add more automation around provisioning, like conditionally running migrations or creating demo content.

➡️ See Development > Provision

Settings management

Vortex includes a structured way to manage Drupal settings per environment. Here's how it works:

  • The environment type (e.g. local, CI, stage) is automatically detected based on the environment provider settings located in web/sites/default/includes/providers/.
  • Settings overrides are stored in web/sites/default/includes/modules/ with logic per environment inside each module-specific file.

This structure gives you clarity, avoids config sprawl, and lets you remove a module's settings cleanly when no longer needed.

Vortex also includes tests for these settings to ensure they are loaded correctly in each environment.

➡️ See Development > Settings

Module and theme scaffolds

We include examples of a custom module and theme, each fully integrated with tests. These show you how to:

  • Structure custom features
  • Write functional, kernel, and unit tests
  • Connect theme assets to a build pipeline

Use these scaffolds as starting points for your own work.

➡️ See Development > Modules > Module scaffold and Development > Themes

Code quality and testing

Vortex ships with pre-configured tools for maintaining code quality:

  • PHP CodeSniffer (phpcs)
  • PHPStan
  • Rector
  • Twig CS Fixer
  • ESLint
  • Stylelint

You'll also find scaffolds for:

  • PHPUnit: Unit and kernel testing
  • Behat: Behavior-driven testing with screenshot capture and extra steps
  • Jest: JavaScript unit testing

➡️ See Development > Code quality and Development > Testing

Automated dependency updates

Vortex includes configuration for RenovateBot to automate dependency upgrades:

  • Critical updates checked daily
  • Regular updates run weekly
  • PRs include changelogs and pass through your continuous integration pipeline

You can host RenovateBot yourself or use the cloud version, and you can tweak the schedule as needed.

➡️ See Development > Dependency updates

Environment variables

Vortex uses environment variables extensively to configure behavior across local, CI, and hosting environments.

These variables are either defined in the .env file or set within CI/hosting environments as secrets.

➡️ See Variables

Continuous integration workflows

Vortex supports GitHub Actions and CircleCI. You choose which one to use in your project. These pipelines include:

  • Database fetch and caching (for faster builds)
  • Full site provisioning in CI
  • Running code quality checks
  • Running unit, functional and behavior tests
  • Triggering deploys when tests pass

Each continuous integration configuration mirrors what happens locally and in hosting to ensure uniformity.

➡️ See Continuous Integration

Hosting integrations

Out of the box, Vortex supports Acquia and Lagoon hosting. These integrations:

  • Trigger provisioning with the same steps used locally and in CI
  • Provide deployment pipelines suited to each platform

You can use Vortex with other platforms too, but these are first-class integrations.

➡️ See Hosting

Documentation & onboarding

Vortex includes centralized documentation (what you're reading now), as well as a scaffold for adding project-specific docs within your own repository.

Testing the template

Vortex itself is tested at multiple levels to ensure the template and its automation scripts work correctly:

  • Unit tests: Shell scripts are tested in isolation using Bats with mocked commands
  • End-to-end tests: Full build pipelines are tested using PHPUnit in real Docker containers
  • Real-world validation: The DrevOps website serves as a production reference site that receives regular upstream updates

➡️ See Contributing > Maintenance > Template