Magento best practices

Performance and stability best practices for Magento 2 / Adobe Commerce on TurboStack - Redis, Varnish, Elasticsearch, OPcache, cron and production mode.

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.

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 production for 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 sequence setup:upgrade -> setup:di:compile -> setup:static-content:deploy -> cache:flush (use setup:upgrade --keep-generated on 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 the env.php cache 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/static and pub/media via 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 --user services rather than relying only on cron, so they restart on failure. See Message-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',
                ],
            ],
        ],
    ],
];
  • database keeps the two caches apart (0 for the default cache, 1 for the full-page cache); id_prefix keeps keys unique when several sites share the instance.
  • default_lifetime is the Time to Live (TTL) in seconds for keys with no explicit expiry. min_lifetime and max_lifetime bound the lifetime for the default cache.
  • compress_data set to 1 shrinks 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
  • %i is the consumer name, so one template serves every queue, and %h is your home directory.
  • --single-thread runs one thread per process; --max-messages=10000 restarts 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):

Variable Tune when
mysql_innodb_size The InnoDB buffer pool is too small for your catalog/order volume
redis_memory Redis is evicting keys under load
elasticsearch_heap_size Search is slow or the catalog is very large
varnish_cache_size The page cache hit ratio is low because the cache is too small

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, and var directories.
  • 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.