Frameworks
Govard detects supported frameworks and applies runtime defaults plus version-aware overrides.
Support Matrix
| Framework | Auto-Detection | Version-Aware Profile | Default Web Root | Audit Lint (govard) |
|---|---|---|---|---|
| Magento 2 | ✅ | ✅ | /pub | ✅ |
| Mage-OS | ✅ | framework defaults | /pub | ✅ (via Magento 2) |
| Magento 1 / OpenMage | ✅ | framework defaults | project root | — |
| Laravel | ✅ | ✅ | /public | ✅ |
| Next.js | ✅ | framework defaults | project root | — |
| Emdash | ✅ | framework defaults | project root | — |
| Drupal | ✅ | ✅ | /web | — |
| Symfony | ✅ | ✅ | /public | ✅ |
| Shopware | ✅ | framework defaults | /public | — |
| CakePHP | ✅ | framework defaults | /webroot | — |
| PrestaShop | ✅ | framework defaults | project root | — |
| WordPress | ✅ | ✅ | / | ✅ |
| Django | ✅ | framework defaults | project root | — |
| Dagster | ✅ | framework defaults | project root | — |
| Custom | manual | manual | project root | — |
Linter column:
Audit Lint (govard)showsgovard audit run --checks lintsupport. ✅ = nativegovardprovider (Magento2:Magento2CS, Laravel:PSR12, Symfony:Symfony, WordPress:WordPress); every lint run also enforces the media guard (pub/media*.php/*.phtml/*.pht→M2-LINT-MEDIAfailed, containermedia-guardphase plus hostScanMediaGuardfallback) and hygiene.gitignore(pub/media/*.phpetc. viainternal/blueprints/files/.gitignore). See Audit — Lint & Profiler.
Runtime Defaults
| Framework | PHP | Node | Python | DB | Cache | Search | Queue |
|---|---|---|---|---|---|---|---|
| Magento 2 | 8.4 | 24 | — | mariadb 11.4 | valkey 8.0.0 | opensearch 2.19.0 | none |
| Mage-OS | 8.4 | 24 | — | mariadb 11.8 | redis 7.4 | opensearch 3.0 | none |
| Magento 1 / OpenMage | 8.1 | — | — | mariadb 10.11 | none | none | none |
| Laravel | 8.4 | — | — | mariadb 11.4 | none | none | none |
| Next.js | — | 24 | — | none | none | none | none |
| Emdash | — | 22 | — | none | none | none | none |
| Drupal | 8.4 | — | — | mariadb 11.4 | none | none | none |
| Symfony | 8.4 | — | — | mariadb 11.4 | none | none | none |
| Shopware | 8.4 | — | — | mariadb 11.4 | none | none | none |
| CakePHP | 8.4 | — | — | mariadb 11.4 | none | none | none |
| PrestaShop | 8.1 | — | — | mariadb 10.11 | none | none | none |
| WordPress | 8.3 | — | — | mariadb 11.4 | none | none | none |
| Django | — | — | 3.12 | postgres 16 | none | none | none |
| Dagster | — | — | 3.12 | postgres 16 | none | none | none |
| Custom | 8.4 | — | — | mariadb 11.4 | none | none | none |
— means Govard does not force a default for that stack component.
Version-Aware Overrides
| Framework | Version | PHP Override | Other |
|---|---|---|---|
| Laravel | 10 | 8.1 | |
| Laravel | 11 | 8.3 | |
| Laravel | 12 | 8.4 | |
| Symfony | 6.0-6.3 | 8.1 | |
| Symfony | 6.4+ | 8.2 | |
| Symfony | 7.0-7.1 | 8.2 | |
| Symfony | 7.2+ | 8.3 | |
| Drupal | 10 | 8.3 | |
| Drupal | 11 | 8.4 | |
| WordPress | 6.0 | 8.0 | MariaDB 10.6 |
| WordPress | 6.3 | 8.1 | MariaDB 10.6 |
| WordPress | 6.4-6.5 | 8.2 | MariaDB 10.11 |
| WordPress | 6.6+ | 8.3 | MariaDB 10.11 |
| WordPress | 6 (bare) | 8.3 | MariaDB 10.11 — bare major resolves to latest minor (6.6+) |
| WordPress | 7 | 8.4 | MariaDB 11.4 |
| Magento 2 | 2.4.9+ | 8.4 | MariaDB 11.4, Redis 7.2, OpenSearch 3.0.0, RabbitMQ 4.1.0 |
| Magento 2 | 2.4.8 | 8.4 | MariaDB 11.4, Redis 7.2, OpenSearch 2.19.0 or 3.0.0 |
| Magento 2 | 2.4.7 | 8.3 | MariaDB 10.6 or 10.11, Redis 7.2, OpenSearch 2.12.0-2.19.0 |
| Magento 2 | 2.4.6 | 8.2 | MariaDB 10.6 or 10.11, Redis 7.0-7.2, OpenSearch 2.5.0-2.19.0 |
Audit lint:
govard audit run --checks lint(providergovard) is supported for Magento 2, Laravel, Symfony, and WordPress — 4 frameworks.audit lint supported for 4. Imagegovard-glintbundles native coding standards (WPCS 3.1 for WordPress, Symfony CS for Symfony, PSR12 for Laravel, Magento2 for Magento) +phpstan/phpstan-symfony+phpstan/phpstan-wordpressso WordPress/Symfony run natively without fallback to PSR12.
# Inspect the resolved profile
govard config profile --json
govard config profile --framework laravel --framework-version 11 --json
# Matrix: ProjectPHPVersions [8.1-8.4], PHPStanLevel 5, Linters [phpcs,phpstan]🧱 Magento 2
Magento 2 is the deepest supported workflow in Govard.
Key Features
govard config autoinjects DB, cache, search, Varnish, and base URLs intoapp/etc/env.phpgovard tool magento [command]runs Magento CLI (bin/magento) inside the PHP containergovard tool magerun [command](Shortcut:mr) runsn98-magerun2inside the PHP containergovard tool magento cron:installinstalls crontabs inside the container- Optional Selenium/MFTF support (
mftf: truein features) - Optional built-in frontend synchronization (
frontend_sync: truein features) - Dedicated
php-debugrouting when Xdebug is enabled
Typical Flow
govard env up
govard config auto
govard tool magento cache:clean
govard test phpunit🏎️ Frontend Synchronization
Magento 2 and Mage-OS projects can opt into Govard's built-in BrowserSync frontend synchronization:
stack:
features:
frontend_sync: truefrontend_sync defaults to false and is invalid for other frameworks. It enables explicit, project-owned frontend runtime discovery. govard env up never starts or allocates frontend development services and always routes the project domain to web or Varnish; the on-demand frontend lifecycle is managed separately.
Hyva projects require exactly one scripts.browser-sync owner below app/design/frontend/<Vendor>/<Theme>/web/tailwind; every discovered Tailwind package needs a committed package-lock.json. Luma projects require root Gruntfile.js, package.json, and package-lock.json (Magento ships these as .sample files — copy them and run npm install to generate the lockfile); Magento's default Gruntfile/LiveReload setup needs no further changes. A project may not satisfy both Hyva and Luma discovery at once; remove one setup before starting frontend sync. Govard does not create or edit BrowserSync, Magento, or theme files in your project.
Luma needs no project-specific BrowserSync config, but Hyva's browser-sync.config.js (owned by the theme, not Govard) must read the environment Govard injects and use these settings to work correctly as a reverse proxy in front of the real application:
module.exports = {
proxy: {
target: process.env.GOVARD_FRONTEND_SYNC_TARGET, // Govard sets this to the app container
proxyOptions: { changeOrigin: false }, // keep the original Host header
cookies: { stripDomain: false }, // keep Magento's session cookie domain intact
},
port: Number.parseInt(process.env.GOVARD_FRONTEND_SYNC_PORT || '3000', 10),
open: false, // no display inside the container
socket: {
domain: "//'+location.host+'", // resolve at request time via Caddy
path: '/browser-sync/socket.io', // must match the /browser-sync/* route
},
};changeOrigin: false and cookies.stripDomain: false are the two settings that matter most: with either wrong, BrowserSync sends Magento a Host header or cookie scope that does not match the browsing domain, which can trigger Magento's own base-URL redirect or break session cookies even though frontend start reports success. open: false avoids BrowserSync trying to launch a browser inside the headless Node container. socket.path must stay /browser-sync/socket.io since that is the only path Govard's Caddy route proxies to the BrowserSync container.
Switching the active Hyva theme
Because discovery requires exactly one scripts.browser-sync owner, a project with multiple Hyva themes can only drive frontend sync from one of them at a time. To switch: remove (or rename) the scripts.browser-sync entry in the currently active theme's web/tailwind/package.json, add the same script (plus its own browser-sync.config.js, package.json scripts, and package-lock.json) to the target theme, then run govard frontend start again — it re-discovers whichever theme is now the sole owner.
A theme that only inherits another Hyva theme via theme.xml's <parent> (and does not override web/tailwind itself) shares that parent's compiled CSS and does not need its own BrowserSync setup at all; frontend sync for the parent theme already covers it through Magento's own static-file fallback.
A non-Hyva theme (Luma-based, no Hyva_Theme dependency) cannot be driven through the Hyva path above — it needs the Luma prerequisites (root Gruntfile.js/package.json/package-lock.json) instead, and Hyva/Luma discovery remains mutually exclusive project-wide: only one of the two setups may be valid at a time.
After govard env up, use govard frontend start; use govard frontend logs [service] -f for BrowserSync, LiveReload, its HTML injector, or a discovered watcher (services are named sync, watch-<theme>, and inject — containers come out as <project>-frontend-sync-1, etc.), and govard frontend stop to remove only frontend services while retaining their dependency volumes. While active, Caddy routes Hyva /browser-sync/* requests to port 3000 and Luma /livereload/* requests to port 35729 for client assets and the socket; both modes also send all other application traffic through their own dedicated injector, which buffers only HTML responses to insert their client script (BrowserSync's or the standard LiveReload client) before </body> and passes non-HTML bodies through unchanged. Stopping restores the normal application route before the frontend containers are removed.
Native Upgrade Pipeline
# Test upgrade in an isolated profile
cp .govard.yml .govard.upgrade-test.yml
GOVARD_ENV=upgrade-test govard upgrade --version 2.4.8-p4 --dry-run
GOVARD_ENV=upgrade-test govard upgrade --version 2.4.8-p4What govard upgrade does for Magento 2:
- Resolves correct PHP/MariaDB/Search versions for the target
- Smart Composer merge (preserves your modules and custom repos)
- Automatically relaxes version constraints for dev tools (
phpunit,phpmd) - Handles
composer update,setup:upgrade, and static content compilation
Multi-Website / Multi-Store Setup
framework: "magento2"
domain: "primary.test"
store_domains:
store-a.test:
code: base
type: website
store-b.test:
code: store_b
type: storegovard domain add store-a.test
govard domain add store-b.test
govard config auto
govard tool magento cache:flushWhat Govard handles automatically:
- Routes all domains through the shared proxy with HTTPS
- Sets global base URL from
domain - Runs scoped
bin/magento config:setfor eachstore_domainsentry - Emits
MAGE_RUN_CODE/MAGE_RUN_TYPEhost mappings (object form with explicittype)
What you still need to do:
- Create websites, stores, and store views in Magento admin
- Clear config/cache after changing store mappings
🌱 Mage-OS
Mage-OS is a community-maintained, drop-in fork of Magento 2 Open Source. Govard detects it via mage-os/product-community-edition or mage-os/project-community-edition in composer.json, and reuses Magento 2's Docker image, nginx template, and Varnish/compose stack — all Magento 2 tooling above (govard tool magento, govard tool magerun, govard config auto, multi-site routing) applies unchanged.
Default runtime: PHP 8.4.
Fresh Bootstrap & Native Upgrade Pipeline
govard bootstrap --framework mageos --fresh
govard upgrade --version 1.3.1govard bootstrap/govard upgrade use mage-os/project-community-edition and Mage-OS's public repository (https://repo.mage-os.org) instead of Magento's private repository.
🛒 Magento 1 / OpenMage
govard tool magerun [command]Default runtime: PHP 8.1 + MariaDB 10.11. No optional cache/search/queue services forced.
Native Upgrade Pipeline
govard upgrade --version <version>Handles: Composer sync, cache purge (var/cache, var/session, etc.), compiler maintenance, and DB migration via n98-magerun.
Multi-Store with Typed Routing
framework: "magento1"
domain: "primary.test"
store_domains:
store-a.test:
code: base
type: website
store-b.test:
code: store_b
type: store
store-c.test: store_c # scalar = legacy behavior (try both website + store code)Object form with explicit type causes Govard to inject host-based MAGE_RUN_CODE / MAGE_RUN_TYPE into nginx/Apache automatically — no manual .htaccess SetEnvIf rules needed.
🎨 Laravel
govard tool artisan [command]Defaults: web root /public, MariaDB 11.4, version-aware PHP.
Native Upgrade Pipeline
govard upgrade --version 12- Updates
composer.jsonframework constraint - Runs full
composer update - Runs
php artisan migrate --force
🌐 Drupal
govard tool drush [command]Defaults: web root /web, MariaDB 11.4, version-aware PHP.
⚡ Symfony
govard tool symfony [command]Defaults: web root /public, MariaDB 11.4, version-aware PHP.
Native Upgrade Pipeline
govard upgrade --version 7- Updates
symfony/framework-bundleconstraints - Runs
composer update - Runs
doctrine:migrations:migrate - Runs
cache:clear
🛍️ Shopware
govard tool shopware [command]Defaults: web root /public, MariaDB 11.4, PHP 8.4.
🍰 CakePHP
govard tool cake [command]Defaults: web root /webroot, MariaDB 11.4.
🏪 PrestaShop
govard tool prestashop [command]Defaults: web root project root, MariaDB 10.11, PHP 8.1. Govard auto-detects PrestaShop projects and clones/configures existing installs; there is no fresh-install bootstrap or native upgrade pipeline for PrestaShop yet.
📰 WordPress
govard tool wp [command]Defaults: web root /, MariaDB 11.4, PHP 8.3.
Fresh Bootstrap
WordPress fresh bootstrap downloads core from wordpress.org and installs via PHP bootstrap scripts — wp-cli is not required for initial setup.
govard bootstrap --framework wordpress --freshNative Upgrade Pipeline
govard upgrade --version 6.7wp core update --version=<version>wp core update-dbwp cache flush
⚡ Next.js
govard shell # opens web container at /app
govard tool npm [command]
govard tool npx [command]Defaults: Node 24, no DB forced. Project-root web serving. govard tool npm and govard tool npx use the configured standalone Node image; govard shell continues to open the application web container.
🔵 Emdash
Node-first local runtime: Node 22, no managed PHP/DB/cache/search/queue.
govard shell # web container at /app
govard tool pnpm [command]
govard open admin # opens /_emdash/adminFresh install:
govard bootstrap --framework emdash --fresh
govard env upPackage manager auto-detection: Govard reads package.json (packageManager field), pnpm-workspace.yaml, and lockfiles.
Current scope is local Node + SQLite + local uploads. Govard does not yet automate Cloudflare D1/R2 flows.
🐍 Django
Python-first local runtime: Python 3.12 (configurable via stack.python_version), PostgreSQL 16, no managed PHP/cache/search/queue.
govard shell # web container at /app
govard tool manage [command] # python manage.py [command]
govard db connect # psql into the postgres dbFresh install (scaffold a brand-new project from scratch):
mkdir myproject && cd myproject
govard init --framework django
govard bootstrap --fresh --framework django --framework-version 5.1Fresh install (clone an existing project, then bootstrap it):
git clone <your-django-repo> myproject && cd myproject
govard init --framework django
govard env up
govard bootstrap --framework djangoDetection: any project with a manage.py file at its root.
Current scope is
requirements.txt+piponly (no Poetry/pyproject.toml), PostgreSQL only (no SQLite/MySQL option), andmanage.py runserverfor local dev (no Gunicorn). Both workflows runpip install+manage.py migrateautomatically.--freshscaffolds viadjango-admin startproject config .and wiressettings.pyto the Postgres container Govard already provisions, plusALLOWED_HOSTS/CSRF_TRUSTED_ORIGINSfor the project's configured domain.
⚙️ Dagster
Python-first local runtime: Python 3.12 (configurable via stack.python_version), PostgreSQL 16, no managed PHP/cache/search/queue.
govard shell # web container at /app
govard tool dagster [command] # dagster CLI commands
govard db connect # psql into the postgres dbFresh install (scaffold a brand-new project from scratch):
mkdir myproject && cd myproject
govard init --framework dagster
govard bootstrap --fresh --framework dagsterFresh install (clone an existing project, then bootstrap it):
git clone <your-dagster-repo> myproject && cd myproject
govard init --framework dagster
govard env up
govard bootstrap --framework dagsterDetection: any project with a workspace.yaml or dagster.yaml file at its root.
Current scope is
requirements.txt+piponly (no Poetry/pyproject.toml) and PostgreSQL only, viadagster-postgres. Both workflows runpip installautomatically.--freshscaffolds viadagster project scaffoldand writesdagster.yaml(Postgres storage config wired to the container Govard already provisions) plus aworkspace.yamlpointing at the scaffolded module. The compose blueprint also mounts and trusts Govard's local root CA inside the container, so outbound HTTPS calls to other Govard projects vialinked_projectsverify correctly.
🔧 Custom Stack
govard init --framework customInteractive picker for:
- Web server (
nginx,apache,hybrid) - Database engine and version
- Cache service
- Search engine
- Queue service
- Optional Varnish
Contributing a New Framework
Want to add a framework not listed here? See Adding a New Framework for the internal registry structure and a file-by-file guide.