Essential Tools for PrestaShop Development
Curated toolkit for PrestaShop developers — code editors, debugging, database tools, image editing, version control, and our recommended open source stack.
The tools we actually open every day
This is the toolbox 151 shipped modules and a decade of PrestaShop work has narrowed us down to. Not "top 10" filler — the specific things we keep running on the TrueNAS box that hosts our 100+ Docker containers, plus the small handful of desktop apps we open before the first coffee.
Some of these we recommend without hesitation. A few we tried, dropped, and replaced with something simpler. We'll tell you which is which.
Editor
VS Code over PhpStorm — but only just
We run VS Code on an Arch Linux desktop, connected via the Remote-SSH extension to the TrueNAS server where every Docker container lives. The whole module tree opens as if it were local, with PHP Intelephense indexing PrestaShop's class hierarchy in the background. That setup has handled every module we've shipped since 2022.
We tried PhpStorm seriously — twice. Its PHP understanding is genuinely deeper out of the box, and the database tools are excellent. But it eats 3-4GB of RAM per project, the indexing pauses are real on large PrestaShop trees, and once you've put time into Intelephense + a couple of Smarty extensions, the gap closes. We pay for the Intelephense premium license; it costs $25 once and the rename refactoring alone pays for itself the first time you touch a trait used by 12 modules.
The extensions worth installing on day one:
- PHP Intelephense — autocomplete that actually understands
$this->context->cart->id_customer - Smarty Template Support — without this,
.tplfiles are uncoloured noise - GitLens — "who broke this and when" inline. Indispensable when a module worked last week and now doesn't
- Remote-SSH — the whole reason we picked VS Code
- PHP Debug — Xdebug listener, covered below
One thing we don't bother with: the Docker extension's GUI. sudo docker exec -w "$PWD" dev-tools … from an integrated terminal is faster than clicking through panels.
Xdebug + VS Code — the setup that pays for itself in a week
Step debugging turns "why is this hook returning null?" from a 30-minute hunt into a 2-minute answer. The trick is configuring it so it stays out of the way until you want it.
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
}
}
]
}
Inside the PHP container:
xdebug.mode=debug
xdebug.start_with_request=trigger
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
Use start_with_request=trigger, never =yes. The "yes" variant fires Xdebug on every image request, every AJAX call, every cron — and on a busy dev container that turns the shop into syrup. Trigger mode waits for the Xdebug Helper cookie before it does anything.
Version control
Git, GitHub, semantic versioning. There's no debate here.
Every module lives in its own repo at ~/modules/<name>/, every shared package at ~/packages/<name>/. Tags match the $this->version string in the module's main PHP file — if a client says "the version from three months ago broke X," we check out the exact tag in seconds. Commit messages get the conventional-commit treatment (feat:, fix:, refactor:) because "fixed bug" tells you nothing when you're auditing a six-month-old regression.
GitHub for everything public. We ran Gitea for a while as a private mirror (it's lightweight and a single Docker container) but in the end GitHub's free private repos plus Actions made the extra service redundant. If you have a strong reason to self-host (compliance, air-gapped network), Gitea is the right answer; otherwise stay with GitHub.
Always commitcomposer.lock.composer installreads it;composer updateregenerates it. We've had production deploys break because a freshcomposer installpulled a minor version with a behaviour change — the lock file is what prevents that.
Docker — and one thing we don't do with it
PrestaShop 1.6 wants PHP 7.1. PrestaShop 9.1 wants PHP 8.2+. Running all of these on one host without containers is not a thing we'd attempt. Our TrueNAS box runs 25+ PrestaShop containers (1.6.1.23 through 9.1) each with its own DB, on its own port, on the shared ps-shared network. Nothing conflicts.
Here's the part where we differ from most tutorials: we don't use Docker Compose for the dev stack. We tried it for a year. The problem is that Compose files want to own the lifecycle of a group of containers, and our reality is dozens of long-lived, independently-managed instances that need to come up and down on different schedules. We ended up with a wall of compose files that each described one container, which is the worst of both worlds.
What replaced it: a thin shell wrapper that does docker run with the network, volume, and label flags we always want. Each container is its own discrete thing. We can docker restart ps8-dev without touching the database container, and we never accidentally take down five sites because a sibling crashed during a docker compose up.
If you're starting from scratch on a single project, Compose is fine. If you're going to end up managing 20+ shops, skip it.
# Connect to a containerized DB
sudo docker exec ps8-dev-db mysql -u root -p prestashop
# Run composer through our dev-tools container
sudo docker exec -w "$PWD" dev-tools composer install --no-dev
# Tail logs from a misbehaving container
sudo docker logs -f --tail 200 ps9-dev
Podman exists, we know. For a daemonless, rootless container runtime it's solid. We've never had a reason to switch — every PrestaShop tutorial, every Dockerfile in the ecosystem, assumes Docker. The compatibility tax isn't worth paying.
Database
mysql CLI first, GUI second
For 80% of what we do (checking config values, finding orphan rows, watching SHOW PROCESSLIST during a slow import) the CLI is faster than any GUI. You're already in a terminal:
# Inside a container
sudo docker exec ps8-dev-db mysql -u root -p prestashop
SELECT name, value FROM ps_configuration WHERE name LIKE '%SMTP%';
SELECT COUNT(*) FROM ps_product WHERE active = 1;
SHOW FULL PROCESSLIST;
DBeaver when relationships matter
The moment you're writing joins across ps_product, ps_product_lang, ps_product_shop, ps_stock_available, and ps_image_lang (and that's basically any non-trivial PrestaShop query) DBeaver's autocomplete and ER diagrams earn their keep. SSH tunnelling is built in, so we connect straight to remote client databases without faffing with port forwards.
We tried MySQL Workbench. It's slower, the UI feels older, and the SSH tunnel implementation has bitten us with random disconnects. DBeaver replaced it.
phpMyAdmin — you will end up using it
Every cPanel shared host bundles it. When a client's only access is cPanel, phpMyAdmin is what you've got. It's fine. It does the job. Don't install it on your own dev box though — DBeaver is better in every way that matters.
mysqldump for backups
# Always --single-transaction for InnoDB (PrestaShop uses InnoDB)
mysqldump -u root -p --single-transaction prestashop \
| gzip > backup_$(date +%Y%m%d).sql.gz
# Structure only — useful for diffing schemas across PrestaShop versions
mysqldump -u root -p --no-data prestashop > schema.sql
Without --single-transaction, a backup taken during active orders contains inconsistent rows across ps_orders, ps_order_detail, and ps_stock_available. We learned that the hard way restoring a Friday-night dump that had three orders in limbo.
PHP toolbox
Multiple PHP versions — and why we don't bother locally
The classic advice is "install PHP 7.4, 8.1, 8.2, 8.3 side by side with ondrej/php." We don't. Each Docker container ships its own PHP version; the matrix is taken care of by the container, not the host. Our host runs one PHP version (currently 8.4 in the dev-tools container) for tooling (Composer, PHPStan, grunt scripts) and that's it.
If your workflow is bare-metal LAMP on a laptop, sure, install the PPA. If you're already on Docker, don't.
Composer — with one trap
Composer 2 is non-negotiable for any modern PrestaShop module. It manages autoloading, dependencies, the lot. One thing specific to our setup that we'll flag because we've stepped in it: in our modules, several shared packages (prestashop-admin, prestashop-integrity, prestashop-license, and friends) live in vendor/myprestarocks/ but are synced via scripts, not declared in composer.json. A bare composer install deletes them, the autoloader 500s on the next request, and you're hunting a phantom bug.
Either declare every dependency in composer.json, or build a sync step into your release workflow. Don't mix the two without remembering which packages are which.
PHPStan — start low, climb slowly
PHPStan catches the bugs that live in branches you don't usually hit — null on a possibly-null object, return type mismatch, dead code. We run it at level 5 on most modules. Level 8 is achievable on greenfield code, less so on anything that touches PrestaShop's legacy ObjectModel classes, which still leak mixed types everywhere.
composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse src/ --level=5
Psalm is the alternative. Both are excellent. PHPStan has the bigger community and more PrestaShop-specific extensions floating around; that's why we use it.
PHP_CodeSniffer — for Addons submissions
If you sell modules through PrestaShop Addons, your code has to pass the PrestaShop coding standard. phpcs + phpcbf is the loop:
vendor/bin/phpcs --standard=PSR12 src/
vendor/bin/phpcbf --standard=PSR12 src/
Beyond Addons submissions, consistent style is mostly about diff hygiene. When every file follows the same patterns, real changes stand out in PRs instead of being buried under whitespace noise.
OPcache — not a tool you install, but one you keep aware of
OPcache is on by default in every modern PHP container. Two things bite us repeatedly: web pool OPcache holds stale bytecode after a deploy (the cache has to be reset or you're running the old code), and CLI and web pools have separate caches (clearing one doesn't clear the other). Build a "reset OPcache after deploy" step into every release script. We learned this once, then learned it again, then put it in shell aliases.
Browser tools
Chrome DevTools — the tabs we actually use
The Network tab is the single most-opened thing across our team. Filter to XHR, watch the AJAX cascade during an add-to-cart, find the request that's returning 200 with HTML when it should return JSON. Almost every "checkout is broken" ticket starts here.
After that: Console for the JS errors PrestaShop's front-end modules throw and that users never report; Elements to live-edit CSS before touching template files; Application to nuke a stuck cart cookie; Performance when a page feels slow but the server says it's fine (it's almost always render-blocking JS). Lighthouse is in the Audits tab — we run it on homepage, category, and product. Those three cover 90% of real-user paths.
Playwright over Selenium, every time
Playwright handles PrestaShop's AJAX-heavy pages without the timing dance Selenium forces on you. The auto-wait mechanism just works. We use it for regression suites on Checkout Revolution and Performance Revolution — those two modules touch enough of the checkout flow that we can't ship them without an automated end-to-end pass.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://localhost:8080/en/2-home-accessories.html');
await page.click('.product-miniature:first-child a');
await page.click('.add-to-cart');
await page.waitForSelector('.cart-products-count');
const cartCount = await page.textContent('.cart-products-count');
console.log(`Cart items: ${cartCount}`);
await browser.close();
})();
Same script runs against Chromium, Firefox, and WebKit. Selenium will still be alive in 10 years and that's fine — we're just not using it.
Chrome DevTools MCP + Claude Code — the new entry on this list
This is the one that has genuinely changed our debugging workflow this year. We run Claude Code with the Chrome DevTools MCP server, which lets Claude drive a real browser — take screenshots, read console messages, inspect network requests, evaluate scripts in the page context. "Open the cart, add this product, screenshot the checkout step, and tell me why the discount code isn't applying" works as a single instruction.
It's not replacing the human at the wheel. It's removing the part where you context-switch between editor and browser fifteen times an hour. For CSS bugs especially, getting Claude to verify a deploy via the live DOM is faster than refreshing yourself.
Graphics
GIMP for raster, Inkscape for vector — and Photopea when we're in a hurry
GIMP 3.0 (released in 2025) finally fixed the worst of the UI ergonomics and PSD compatibility. We use it for product image edits, banners, admin icons. Is it Photoshop? No. Does it handle every PrestaShop image task? Yes.
Inkscape produces the cleanest SVG output of anything we've tried — admin icons go straight from Inkscape into module templates. The SVG output is small enough that we inline it into Smarty rather than serving as a file.
Photopea is the one we open more than we expected to. Browser-based, opens PSDs, runs entirely client-side. When a client sends a PSD comp and we need one layer exported, opening Photopea is faster than launching GIMP. For our 3D box-cover automation (driven by Photopea's scripting API), it's actually doing real work on every release.
ImageMagick — the headless workhorse
5,000 product images at 4000x4000 needing to be 800x800 WebP versions? mogrify in a loop. This is one of the rare cases where the CLI tool is not just acceptable but actually the right answer:
# Resize all to 800x800, 85% JPEG quality
for f in *.jpg; do
convert "$f" -resize 800x800 -quality 85 "resized/$f"
done
# PNG to WebP, same visual quality, ~30% smaller
convert product.png -quality 80 product.webp
# Square thumbnails for category pages
mogrify -resize 300x300^ -gravity center -extent 300x300 -path thumbs/ *.jpg
We've inherited image-processing pipelines built in Node with sharp and another in Python with Pillow. Both work. Neither is faster than calling convert from bash. For batch operations where you don't need pixel-level control, ImageMagick is the answer.
Server infrastructure
TrueNAS + ZFS — the foundation
The whole dev environment lives on a TrueNAS box with 64GB RAM. ZFS gives us two things we'd struggle to replace: snapshots (we can rewind the entire Docker dataset to "before that risky module upgrade" in seconds) and end-to-end checksums (silent bit-rot is caught and corrected automatically — that matters when this disk holds every module we sell).
The Docker data root lives on the SSD pool. We run with live-restore enabled so a Docker daemon restart doesn't take every container down.
Nginx Proxy Manager — and the one rule
NPM gives us clean URLs (ps82.dev.mypresta.rocks, ps91.dev.mypresta.rocks) with automatic Let's Encrypt SSL across 25+ instances. The web UI is genuinely good — no Nginx config files to hand-edit.
One rule we will not break: never docker network connect or disconnect the NPM container while it's running. The container is fine; the iptables rules don't recover; port 443 stops responding; every site goes down. Take NPM offline cleanly, change networks, bring it back. If you've ever wondered why your reverse proxy randomly stopped serving HTTPS, this is it.
WireGuard — every laptop has it
WireGuard configs are 10 lines and connect instantly. Compared to OpenVPN it's both faster and less fiddly. Every team laptop has a peer entry; the dev server lives behind a home firewall and is reachable from any coffee shop without forwarding ports.
Rclone for off-site backups
Module ZIPs and database dumps sync to Backblaze B2 nightly. Rclone speaks 70+ providers; we picked B2 for the price. The cron line is:
rclone sync ~/releases/ b2:mpr-releases/ --progress
rclone copy ~/backups/db/ b2:mpr-db-backups/
Off-site backup is not a feature you wait until you need. The first time you need it, it's too late.
Uptime Kuma
One Docker container, knows about every client store and every internal service, pings Discord when something goes red. "We noticed before you called" is a better support experience than "your site has been down for 4 hours, we're looking into it now."
Build tools
Node.js — pin the version
Our containers run Node 20 LTS. The PrestaShop Hummingbird theme's webpack config is sensitive to Node version differences; we've watched a Node 22 upgrade silently break the production build. nvm on bare metal, node:20-bullseye in containers — pin and forget.
Grunt — for module ZIP packaging
Every one of our modules ships with a Gruntfile.js. grunt at the module root: bump version, exclude .git + node_modules + dev files, compile Sass, run the validator, drop a clean ZIP into ~/releases/. Without it the release process is a sequence of manual steps that someone, eventually, gets wrong at 2am.
Webpack runs in Hummingbird (and any child theme we build on top of it). The pre-configured webpack.config.js from PrestaShop core is fine. We rarely touch it.
Dart Sass — and the BOM gotcha
Use Dart Sass. Node Sass and Ruby Sass are dead.
sass src/scss/admin.scss:views/css/admin.css --style=compressed
sass --watch src/scss/:views/css/
One thing that bit us once and only once: Dart Sass can emit a UTF-8 BOM at the start of compiled CSS. On most browsers it's harmless. On one client's setup with a particular nginx + CDN combination, the BOM caused the first CSS rule to be silently dropped. The fix:
sed -i '1s/^\xEF\xBB\xBF//' output.css
If a stylesheet looks broken for no reason, check for a BOM.
Email and communication
Thunderbird is what we use for client mailboxes. IMAP across every domain, OpenPGP built in, calendars via CalDAV. We've tried web clients and they're fine for personal Gmail; for managing 8+ professional mailboxes Thunderbird's unified inbox and filter engine wins.
Discord for the PrestaShop community and for our own team chat. Slack when a client mandates it. Element/Matrix is the right answer for full sovereignty but the network effects of Discord won that fight for us.
For notes, we run an Outline wiki on our own infrastructure — that's where client runbooks, infrastructure docs, and post-mortems live. Plain Markdown README.md files in each module repo cover the per-module documentation. The trick is picking one system and being consistent; the actual choice between Outline, Obsidian, Trilium, and plain Markdown matters less than people think.
Our own scripts
This section doesn't exist in most "developer tools" lists because most lists only cover off-the-shelf software. After ten years on PrestaShop we've accumulated a small library of shell scripts in ~/scripts/ that genuinely save us hours per week:
nuke-module.sh— wipes a module from a container completely: files,ps_module,ps_authorization_role,ps_hook_module, configuration, Smarty cache, OPcache. The only sane way to test an install flow from a truly clean slate when a previous half-failed install has poisoned the database.fix-container-perms.sh— chowns bind-mounted files towww-datainside a container. Solves the "files showing as 3002:3002" problem every time we sync from host into container.sync-prestashop-*.sh— propagates shared packages (prestashop-admin,prestashop-integrity,prestashop-license,prestashop-compat, etc.) from master sources in~/packages/into every module that uses them. Run after fixing a shared bug in one place to push it to all 151 module trees.- The ship/certify/build pipeline — grunt + a few wrapper scripts that bump version, validate the ZIP against PrestaShop's static rules, certify it, sync vendor packages, and push to GitHub in one command.
If you're shipping more than two or three modules, build your own. The investment pays back the first time a release night goes smoothly because no manual step was skipped.
Where to start if you're starting today
The advice list is shorter than it looks:
- Install Docker. Skip Compose unless you'll only ever run one stack.
- Install VS Code with PHP Intelephense, Smarty, GitLens, Remote-SSH, PHP Debug. Configure Xdebug in your PHP container with
start_with_request=trigger. - Git every module repo. Tags match the module's
$this->version. - Add Composer to one module, get autoloading working, copy that pattern to the rest.
- Install GIMP, Inkscape, ImageMagick. You will need them sooner than you think.
- Set up Uptime Kuma the moment you have one production site to watch.
Don't try to adopt the whole list at once. Docker + VS Code + Git + Xdebug is the kernel. Everything else gets layered on as the work demands it.
Related reading
- Docker for PrestaShop: Development Environment Setup — the multi-container setup we run on TrueNAS
- PrestaShop Local Development: XAMPP, WAMP, Docker & Linux Setup — bare-metal alternatives if Docker isn't an option
- PrestaShop Hooks & Overrides: Developer Reference Guide — the debugging targets these tools point at
- PrestaShop Performance Optimization Guide — where Lighthouse and Xdebug profiling earn their keep
- Challenges of PrestaShop Module Development — the wider context for why these specific tools made the cut