From sw6-skills
DDEV local development for Shopware 6 projects. Trigger when the user mentions DDEV, ddev exec, local development setup, watchers, or workers.
How this skill is triggered — by the user, by Claude, or both
Slash command
/sw6-skills:ddevThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The primary reference for DDEV + Shopware is
The primary reference for DDEV + Shopware is https://notebook.vanwittlaer.de/ddev-for-shopware — consult it for detailed setup guides. This skill covers conventions, decisions, and gotchas.
All Shopware commands run via ddev exec.
ddev exec bin/console cache:clear # correct
ddev exec composer require foo/bar # correct
php bin/console cache:clear # WRONG — outside container
name: myshop
type: shopware6
php_version: "8.3"
docroot: shopware/public
composer_root: shopware
working_dir:
web: /var/www/html/shopware
database:
type: mysql
version: "8.4"
nodejs_version: "22"
webimage_extra_packages:
- php${DDEV_PHP_VERSION}-amqp
web_environment:
- APP_ENV=dev
Key choices:
docroot and composer_root point into shopware/ subdirectory (production template layout)php-amqp if using RabbitMQAfter importing a production DB dump, fix domains and rebuild:
hooks:
post-import-db:
- exec: |
mysql -uroot -proot -e "
UPDATE sales_channel_domain
SET url = REPLACE(url, 'https://www.myshop.de', 'https://myshop.ddev.site');
"
bin/console database:migrate --all
bin/console theme:compile
bin/console cache:clear
Reference: https://notebook.vanwittlaer.de/ddev-for-shopware/using-shopware-cli-with-ddev
Install by creating .ddev/web-build/Dockerfile.shopware-cli:
COPY --from=shopware/shopware-cli:bin /shopware-cli /usr/local/bin/shopware-cli
Then ddev restart.
Key commands:
ddev exec shopware-cli project storefront-build
ddev exec shopware-cli project admin-build
ddev exec shopware-cli extension zip MyPlugin # package for store upload
Never run shopware-cli project ci locally — it removes source files as
part of its optimization step. It is meant for Docker builds and CI pipelines
only, where the build context is disposable.
Reference: https://notebook.vanwittlaer.de/ddev-for-shopware/storefront-and-admin-watchers-with-ddev
Configuration differs by Shopware version. Create .ddev/config.watcher.yaml:
web_environment:
- HOST=0.0.0.0
- PROXY_URL=${DDEV_PRIMARY_URL}:9998
- STOREFRONT_SKIP_SSL_CERT=true
web_extra_exposed_ports:
- name: vite-admin
container_port: 5173
http_port: 5172
https_port: 5173
- name: storefront-proxy
container_port: 9998
http_port: 8888
https_port: 9998
- name: storefront-assets
container_port: 9999
http_port: 8889
https_port: 9999
Admin watcher (uses shopware-cli):
ddev exec shopware-cli extension admin-watch custom/static-plugins/MyPlugin/ \
https://myshop.ddev.site \
--listen :5173 \
--external-url https://myshop.ddev.site:5173
Storefront watcher:
ddev exec shopware-cli project storefront-watch
web_environment:
- HOST=0.0.0.0
- PORT=9997
- DISABLE_ADMIN_COMPILATION_TYPECHECK=1
- PROXY_URL=${DDEV_PRIMARY_URL}:9998
- STOREFRONT_SKIP_SSL_CERT=true
web_extra_exposed_ports:
- name: admin-proxy
container_port: 9997
http_port: 8887
https_port: 9997
- name: storefront-proxy
container_port: 9998
http_port: 8888
https_port: 9998
- name: storefront-assets
container_port: 9999
http_port: 8889
https_port: 9999
ddev exec bin/watch-administration.sh # or: composer run watch:admin
ddev exec bin/watch-storefront.sh # or: composer run watch:storefront
Always ddev restart after changing watcher config.
Reference: https://notebook.vanwittlaer.de/ddev-for-shopware/message-queue-setup-with-ddev
For local dev that mirrors production queue behavior:
shopware/bin/run-worker.sh:#!/usr/bin/env bash
while :; do
/usr/bin/php /var/www/html/shopware/bin/console $1 -n
done
Create .ddev/web-build/worker.conf (supervisor config) for scheduled-task:run,
messenger:consume async, and messenger:consume failed.
Create .ddev/web-build/Dockerfile.worker:
ADD worker.conf /etc/supervisor/conf.d
# shopware/config/packages/z-shopware.yaml
shopware:
admin_worker:
enable_admin_worker: false
See the notebook reference for the full supervisor config.
Reference: https://notebook.vanwittlaer.de/ddev-for-shopware/fetch-media-from-production-or-staging-server
Avoids downloading gigabytes of media locally. Create .ddev/nginx/media-redirect.conf:
set $media_proxy_url "https://staging.example.com";
location @mediaserver {
resolver 1.1.1.1;
proxy_pass $media_proxy_url$request_uri;
proxy_set_header Authorization "Basic your-basic-auth-secret";
}
location ^~ /media/ {
access_log off;
expires max;
try_files $uri $uri/ @mediaserver;
break;
}
location ^~ /thumbnail/ {
access_log off;
expires max;
try_files $uri $uri/ @mediaserver;
break;
}
Serves local files when available, transparently proxies to production for the rest. Commit this to the repo — once set up, it just works.
Reference: https://notebook.vanwittlaer.de/ddev-for-shopware/rabbitmq-with-ddev
ddev get b13/ddev-rabbitmq && ddev restart
ddev exec composer require symfony/amqp-messenger
Environment variables (.env.dev):
MESSENGER_TRANSPORT_DSN=amqp://rabbitmq:rabbitmq@rabbitmq:5672/%2f/async
MESSENGER_TRANSPORT_LOW_PRIORITY_DSN=amqp://rabbitmq:rabbitmq@rabbitmq:5672/%2f/low_priority
MESSENGER_TRANSPORT_FAILURE_DSN=amqp://rabbitmq:rabbitmq@rabbitmq:5672/%2f/failed
Management UI: https://myshop.ddev.site:15673 (rabbitmq/rabbitmq)
Requires php-amqp extension — see §2 webimage_extra_packages.
Run Claude Code inside the web container so it shares the project's PHP, Node,
Composer, and database — same environment as ddev exec, no host-side toolchain
drift.
ddev add-on get FreelyGive/ddev-claude-code
ddev restart
ddev claude # launch Claude Code inside the container
First run is an interactive setup (login, model, defaults). State persists in
.ddev/.claude.json and .ddev/.claude/ — survives ddev restart and
ddev delete because it lives next to the project, not in the container.
Inside the session, plain bin/console, composer, npm, mysql work
directly — no ddev exec prefix needed.
Commit / ignore:
.ddev/.claude.json and .ddev/.claude/ — don't commit, they contain
auth + personal settings. Add to .gitignore..ddev/web-build/* it writes) — do
commit, so teammates get the same ddev claude command.Bundled ddev glab (GitLab CLI) with state in .ddev/.glab-cli/ — same
ignore rule.
Add-on listing: https://addons.ddev.com/addons/FreelyGive/ddev-claude-code
For browser-based E2E tests against the storefront or admin.
ddev add-on get codingsasi/ddev-playwright
ddev restart
ddev install-playwright # installs CLI + browser binaries
Day-to-day:
ddev playwright test # run the suite
ddev playwright codegen https://myshop.ddev.site # record a flow
ddev playwright show-report --host=0.0.0.0 # open the HTML report
ddev reinstall-browsers # after Playwright version bump
Defaults: test dir tests/playwright/, scaffolds playwright.config.ts plus
global-setup.ts / global-teardown.ts.
Notes:
.nvmrc to Node 22 (requires Node 20+).
Reconcile with §2's nodejs_version: "22" — the add-on may override it; if
Node is wrong inside the container after install, check .nvmrc first.ddev-playwright-browsers mounted at /opt/playwright-browsers/<version>/,
so multiple projects share one download. The volume survives removing the
add-on from a single project.--ui mode is best run from the host (outside the container) at the project
root — in-container UI mode is awkward over the DDEV port forwarding.Commit tests/playwright/ and playwright.config.ts like any other test
code. The add-on's .ddev/ changes go in web_environment (already
committed via .ddev/config.yaml).
Add-on listing: https://addons.ddev.com/addons/codingsasi/ddev-playwright
Lets Claude Code drive a Chromium instance via @playwright/mcp to navigate
the storefront, resize the viewport, and take screenshots. This is for
visual preview & frontend feedback loops — for running the Playwright test
suite, see §9.
ddev exec prefix.codingsasi/ddev-playwright add-on installed (§9) — it provides
Node, browser system libs, the shared /opt/playwright-browsers/ volume,
and sets PLAYWRIGHT_BROWSERS_PATH in the container env. Install
from the host, because ddev restart rebuilds the web container and
kills any in-container Claude session. Relaunch Claude after the restart..mcp.json (project root){
"mcpServers": {
"playwright": {
"command": "npx",
"args": [
"-y", "@playwright/mcp@latest",
"--headless", "--browser=chromium",
"--no-sandbox", "--ignore-https-errors", "--isolated"
],
"env": { "PLAYWRIGHT_BROWSERS_PATH": "/opt/playwright-browsers" }
}
}
}
The PLAYWRIGHT_BROWSERS_PATH line is only correct with the add-on —
that path is the add-on's shared volume mount. Without the add-on, drop the
env block or the browser won't be found.
Flag rationale:
--no-sandbox — Chromium's userns sandbox doesn't work inside the web
container; without it the browser fails to start.--headless — no display available in the container.--ignore-https-errors — *.ddev.site certs aren't trusted by default.--isolated — fresh profile per session, no state leak between runs.@playwright/mcp@latest pulls whichever Chromium build its bundled
Playwright wants, which often differs from what the add-on pre-installed
(observed: add-on shipped chromium-1223; @playwright/mcp 0.0.75 wanted
chrome-for-testing v1224). First launch errors:
Browser "chrome-for-testing" is not installed
One-time fix — installs the missing build into the shared volume, persists across restarts and across projects:
PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers \
npx @playwright/mcp@latest install-browser chrome-for-testing
Why install at runtime: the persistent volume mount shadows anything
baked into /opt/playwright-browsers at image-build time. Whatever the
add-on pre-installs only matters if the volume is empty; once it exists,
new browser builds must be added via this command (or
ddev reinstall-browsers for the add-on side).
https://<project>.ddev.site/),
never https://localhost — Shopware's Host header matching returns
HTTP 400 for unknown hosts.browser_resize covers viewports — desktop and 375px mobile both
verified. Pair with browser_take_screenshot, then view the PNG.APP_ENV=dev, the Symfony profiler bar sits at the page bottom in
every screenshot. A cookie-consent banner overlays first load — accept
or dismiss it before measuring critical chrome.shopware-cli project storefront-build (or bin/console theme:compile
bin/console cache:clear:all as needed) → screenshot → iterate.A Shopware plugin can declare its MCP server in plugin.json under
mcpServers for one-click distribution. The add-on prerequisite still
applies in the target project, so this skill's recipe stays the right
primary documentation unit.
Reference: https://notebook.vanwittlaer.de/ddev-for-shopware/performance-tweaks
.ddev/php/shopware.ini)assert.active = 0
opcache.interned_strings_buffer = 20
opcache.validate_timestamps = 1 # keep 1 in dev to detect changes
zend.detect_unicode = 0
realpath_cache_ttl = 3600
.ddev/mysql/my.cnf)Remove ONLY_FULL_GROUP_BY from SQL mode, increase group_concat_max_len.
.env.local)For faster local testing with production-like performance:
SQL_SET_DEFAULT_SESSION_VARIABLES=0
APP_URL_CHECK_DISABLED=1
SHOPWARE_CACHE_ID=myshop-local
ddev xdebug on only when neededbin/build-*.sh scripts| File | Commit? |
|---|---|
.ddev/config.yaml | Yes |
.ddev/config.watcher.yaml | Yes |
.ddev/docker-compose.*.yaml | Yes |
.ddev/web-build/* | Yes |
.ddev/nginx/media-redirect.conf | Yes |
.ddev/php/shopware.ini | Yes |
.ddev/mysql/my.cnf | Yes |
.ddev/config.local.yaml | No — personal overrides |
.ddev/.claude.json, .ddev/.claude/ | No — Claude Code auth + settings |
.ddev/.glab-cli/ | No — GitLab CLI auth |
ddev start / stop / restart / poweroff
ddev describe # show URLs and ports
ddev ssh # shell into web container
ddev mysql # interactive MySQL
ddev import-db --file=dump.sql.gz # import DB (triggers hooks)
ddev export-db --gzip --file=dump.sql.gz
ddev xdebug on / off / status
ddev exec bin/console <command>
ddev exec composer <command>
ddev logs -f # follow web logs
ddev logs -s db # database logs
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub vanwittlaer/sw6-skills --plugin sw6-skills