How to Optimize Magento 2 Performance and Improve Page Speed
Magento 2 performance depends on proper configuration of caching, static content delivery, image optimization, and server-level tuning. Out-of-the-box settings are conservative and leave significant room for improvement. This guide covers the most impactful optimizations based on real-world store configurations.
Full Page Cache (FPC)
Full Page Cache is the single most impactful performance feature in Magento 2. When properly configured, FPC serves pages without executing any PHP code, reducing response times from seconds to milliseconds.
Understanding Cache Multipliers
FPC creates a separate cached version of each URL for every combination of customer group, store view, and currency. This means:
- 10,000 product URLs × 4 customer groups × 4 store views = 160,000+ cache entries
For most stores, only the "NOT LOGGED IN" customer group needs cache warming, since logged-in customers represent a small fraction of traffic and their sessions change frequently.
Reducing Cache Entries
Enable "Use same cache for new visitor" in Stores → Configuration → System → Full Page Cache to prevent creating duplicate cache entries for new vs. returning visitors who are not logged in. This alone can cut the number of FPC entries significantly.
FPC Compression
Magento compresses cached HTML before storing it in the backend. The default compression threshold is 20,480 bytes (20 KB), meaning smaller pages are stored uncompressed.
Lower the threshold to 2,048 – 4,096 bytes to compress virtually all HTML pages. Typical HTML pages compress by 60–80%, reducing both storage requirements and network transfer time when using Redis or Varnish as the FPC backend.
See also: Redis Full Page Cache
JavaScript and CSS Optimization
Minification and Merging
Enable these settings under Stores → Configuration → Advanced → Developer → JavaScript Settings and CSS Settings:
- Merge JavaScript Files: Yes
- Enable JavaScript Bundling: No (often causes more problems than it solves)
- Minify JavaScript Files: Yes
- Move JS code to the bottom of the page: Yes
- Merge CSS Files: Yes
- Minify CSS Files: Yes
After changing these settings, deploy static content:
php bin/magento setup:static-content:deploy
php bin/magento cache:flush
Incremental Enabling
Some third-party extensions generate JavaScript that conflicts with merge or minification. If you encounter frontend issues after enabling these settings, turn them on one at a time:
- Enable CSS minification first -- this rarely causes issues
- Enable CSS merge
- Enable JS minification
- Enable JS merge last -- this is the most likely to expose conflicts
If a specific setting causes problems, leave it disabled and investigate which extension is incompatible.
Image Optimization
Images typically account for 50–80% of page weight. Optimizing images provides the largest improvement in perceived page load time.
Key Settings
- Quality: Set JPEG quality to 80%. The visual difference between 80% and 100% is negligible, but file size drops by 40–60%
- Format: Use WebP where possible. WebP images are 25–35% smaller than equivalent JPEGs
- Lazy loading: Enable lazy loading for images below the fold to reduce initial page load time
WebP Conversion
WebP conversion is a background process that runs via cron. After enabling WebP, allow time for the cron to process existing images. For large catalogs, this can take several hours.
Validate that image processing libraries are correctly installed:
php bin/magento mirasvit:optimize-image:validate
This checks for GD, Imagick, and WebP support in the PHP installation.
Redis Configuration
Redis is the recommended cache backend for both default cache and FPC in Magento 2. Incorrect Redis configuration causes cache eviction issues that degrade performance unpredictably.
Eviction Policy
The most common Redis misconfiguration is using volatile-lru as the eviction policy. This only evicts keys with an expiration time set. Magento stores some cache entries without expiration, creating "immortal" keys that Redis cannot evict when memory is full.
Solution: Use allkeys-lru as the eviction policy:
# In redis.conf
maxmemory-policy allkeys-lru
This allows Redis to evict any key when memory pressure is high, preventing out-of-memory errors and stale cache issues.
Separate Redis Instances
Use separate Redis instances (or at least separate databases) for:
- Default cache (db 0)
- Full Page Cache (db 1)
- Session storage (db 2)
This prevents cache flushes from destroying sessions and allows independent memory management.
Cache Clearing Order
When troubleshooting or deploying, clear caches in the correct order:
# 1. Clean Magento cache tags
php bin/magento cache:clean
# 2. Flush entire Magento cache storage
php bin/magento cache:flush
# 3. Flush Redis completely (if using Redis)
redis-cli -n 0 FLUSHDB # default cache
redis-cli -n 1 FLUSHDB # FPC
# 4. Purge CDN/Varnish if applicable
Running cache:clean removes only invalidated entries by tag. Running cache:flush empties the entire cache storage. For a full reset, flush Redis directly and purge any CDN or Varnish layer.
Profiling Performance
Before optimizing, identify where time is being spent. Use the built-in Magento profiler to find slow blocks and queries:
See also: How to Enable Magento 2 Profiler