Magento best practices
Magento 2 (Adobe Commerce) is resource-intensive, placing high demands on memory, CPU, and I/O. A fast, stable storefront depends on the right caching layers, a working cron, and production mode. TurboStack provisions most of this for you; this page covers what is already configured and what to optimize on top.
What TurboStack configures for you
When you deploy a magento2 app, the platform sets up a complete, tuned Magento stack:
- Document root - the vhost serves from the Magento
pub/directory inside your app root (/var/www/<user>/public_html), with a Magento-specific Nginx configuration (50main.conf). - Redis caching - sessions use a dedicated persistent Redis socket, while the default cache and full-page cache use a separate Redis instance. This is configured at install time, so checkout state stays fast and the database is offloaded.
- Varnish full-page cache - when Varnish is enabled, the platform installs a Magento-aware VCL. It configures Magento to use it (
http-cache-hosts,caching_application = 2, backend on port 8080, Varnish on 6081, default Time to Live (TTL) 86400s). - Elasticsearch/OpenSearch - configured as the catalog search engine with a per-site index prefix. Magento requires this; the storefront will not run without it.
- Cron jobs - three cron entries are installed for the system user: the main
bin/magento cron:run,setup:cron:run, and the updater cron. These drive indexing, emails, and scheduled jobs. - Log rotation - everything under the app's
var/log/is rotated weekly via logrotate so disks do not fill up. - Database tuning - a Magento-specific MySQL setting (
restrict_fk_on_non_standard_key = OFF) is applied for compatibility, and OPcache is enabled in the PHP runtime.
Recommended optimizations
Combine Magento's vendor guidance with the TurboStack options below. Most are one toggle away on the host's Services tab.
- Run in production mode - set the deploy mode to
productionfor live stores:bin/magento deploy:mode:set production. This compiles dependency injection (DI) and pre-generates static assets. After deploying code or configuration changes, run the standard sequencesetup:upgrade->setup:di:compile->setup:static-content:deploy->cache:flush(usesetup:upgrade --keep-generatedon production to preserve already-compiled code). - Enable Varnish full-page cache - this reduces time-to-first-byte significantly for storefront pages; keep it on for production.
- Keep Redis on for sessions and cache - already configured; do not switch back to file sessions on a busy store. See
Redis cache tuning for theenv.phpcache block and its lifetime settings. - Keep Elasticsearch/OpenSearch healthy - it is required; size it for your catalog (see below).
- Enable OPcache (and consider the realpath cache) in the PHP runtime to cut PHP parsing overhead.
- Optimize assets and images - minify/merge JS and CSS, use WebP/optimized images, and serve
pub/staticandpub/mediavia a Content Delivery Network (CDN) when possible. - Use an HTTP cache / CDN in front - offload static and media delivery. If a CDN fronts the site, TurboStack can disable Varnish caching of static/media to avoid double caching.
- Keep cron running - reindexing, price rules, emails, and message-queue consumers all depend on cron; never disable it on a live store.
- Run message-queue consumers as services - on a busy store, run consumers as persistent
systemd --userservices rather than relying only on cron, so they restart on failure. SeeMessage-queue consumers below.
Redis cache tuning
TurboStack configures Magento's Redis backends at install time, so you do not set this up by hand. Sessions use the persistent Redis instance; the default cache and full-page cache use the cache instance. The reference below shows the cache block in app/etc/env.php and the values worth tuning (Cm_Cache_Backend_Redis, port 6379, no password):
<?php
return [
'cache' => [
'frontend' => [
'default' => [
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' => [
'server' => '127.0.0.1',
'port' => '6379',
'database' => '0',
'id_prefix' => 'magento_prod_',
'compress_data' => '1',
'default_lifetime' => '600',
'min_lifetime' => '60',
'max_lifetime' => '86400',
],
],
'page_cache' => [
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' => [
'server' => '127.0.0.1',
'port' => '6379',
'database' => '1',
'id_prefix' => 'magento_prod_',
'compress_data' => '0',
'default_lifetime' => '86400',
],
],
],
],
];
databasekeeps the two caches apart (0for the default cache,1for the full-page cache);id_prefixkeeps keys unique when several sites share the instance.default_lifetimeis the Time to Live (TTL) in seconds for keys with no explicit expiry.min_lifetimeandmax_lifetimebound the lifetime for the default cache.compress_dataset to1shrinks the cache at a small processing cost. It is on for the default cache and off for the full-page cache, which is already compact.
After changing env.php, flush the cache:
php bin/magento cache:flush
If caching was not enabled before, turn it on so Redis is actually used:
php bin/magento cache:enable
Message-queue consumers
Magento offloads asynchronous work - reindexing, transactional emails, and order or coupon processing - to message queues handled by consumer processes. On a busy store, run each consumer as a persistent systemd --user service so it restarts on failure, instead of relying on cron alone.
Create a reusable template unit at ~/.config/systemd/user/magento-consumer@.service:
[Unit]
Description=Magento Consumer (%i)
After=network-online.target
Requires=dbus.socket
StartLimitIntervalSec=0
[Service]
Type=simple
WorkingDirectory=%h/public_html
ExecStart=php %h/public_html/bin/magento queue:consumers:start %I --single-thread --max-messages=10000
RestartSec=10s
Restart=always
[Install]
WantedBy=default.target
%iis the consumer name, so one template serves every queue, and%his your home directory.--single-threadruns one thread per process;--max-messages=10000restarts the consumer periodically to keep memory in check.
List the available consumers with php bin/magento queue:consumers:list, then enable and start one service per consumer (the name after @ is the consumer):
systemctl --user enable --now magento-consumer@sales.rule.update.coupon.usage.service
systemctl --user status magento-consumer@product_action_attribute.update.service
To drain queues faster on a busy store, run several consumers in parallel (more instances, or more of the same consumer). Keep the total number of consumers within the host's processor budget: never more than the core count, and keep a margin. Too many will slow the whole store. See Scale throughput with more instances.
For the systemd --user basics - including loginctl enable-linger so the services keep running after you log out - see How to manage user system services.
Sizing and scaling
TurboStack auto-tunes resource limits from the host's size, so start with the defaults. Override the tuning variables only when you have measured evidence (slow queries, cache evictions, search latency):
See Performance tuning before changing any of these. When a single host can no longer keep up, scale up the host before splitting services.
Stability
- Back up regularly - verify scheduled Backups cover both the database and the
pub/media,app/etc, andvardirectories. - Watch Health - monitor CPU, memory, and disk. Magento's
var/and media directories grow over time. - Keep versions current - track Magento/Adobe Commerce security patches and the PHP, MySQL, and Elasticsearch versions you run.
- Test on a staging clone - always trial upgrades, extensions, and theme changes on a copy before publishing to production.
Related
- Deploy Magento
- Magento reference
- How to run multiple Magento store views
- Troubleshooting Magento
- How to manage user system services
- Services
- Performance tuning