DEV Community

Magevanta
Magevanta

Posted on • Originally published at magevanta.com

Magento 2 Cache Warming Strategies: Keep Your Store Fast After Every Deploy

You've spent weeks tuning your Magento 2 Full Page Cache. Varnish is configured, FPC hit rates are above 90%, and your TTFB is under 200ms. Then you deploy a hotfix at 2 AM and flush the cache. Suddenly, every customer who visits gets a cold, uncached response — PHP bootstrapping, layout building, block rendering — the full stack, for every single request.

This is the cold cache problem, and it's one of the most overlooked performance gaps in Magento 2 operations. Cache warming is the solution: proactively generating cached responses before real users arrive.

Why Cache Warming Matters

Magento 2's Full Page Cache is lazy by default. A page only gets cached after the first request hits the backend. On large stores with thousands of product, category, and CMS pages, this means:

  • Every deploy causes a performance cliff until traffic naturally re-warms the cache
  • Cache flushes during low-traffic windows (maintenance, reindexing) leave mornings slow
  • Bots and crawlers that hit un-cached pages waste server resources on expensive renders

A good warming strategy fills the cache before users notice, turning the cold-start problem into a non-event.

Strategy 1: Sitemap-Based Crawling

The simplest and most maintainable approach. Magento generates a sitemap at pub/sitemap.xml (or a sitemap index). Use this as your source of truth.

#!/bin/bash
# warm-cache.sh — crawl all URLs from sitemap

SITEMAP_URL="https://your-store.com/sitemap.xml"
CONCURRENCY=4
USER_AGENT="MagevantaCacheWarmer/1.0"

# Extract URLs from sitemap and crawl with wget
wget -q -O - "$SITEMAP_URL" \
  | grep -oP '(?<=<loc>)[^<]+' \
  | xargs -P "$CONCURRENCY" -I{} \
    curl -s -o /dev/null -A "$USER_AGENT" \
    -H "X-Forwarded-Proto: https" \
    --max-time 10 "{}"

echo "Cache warm complete."
Enter fullscreen mode Exit fullscreen mode

Set CONCURRENCY based on your server capacity. For most stores, 4–8 parallel requests is safe without overwhelming the backend. Run this script immediately after every deploy.

Pro tip: If you have a sitemap index (<sitemapindex>), parse the child sitemaps first:

wget -q -O - "$SITEMAP_URL" \
  | grep -oP '(?<=<loc>)[^<]+\.xml' \
  | xargs -I{} wget -q -O - {} \
  | grep -oP '(?<=<loc>)[^<]+' \
  | xargs -P 4 -I{} curl -s -o /dev/null "{}"
Enter fullscreen mode Exit fullscreen mode

Strategy 2: Magerun2 Integration

If you use n98-magerun2 in your workflow, the sys:url:list command gives you all store URLs programmatically — respecting store views, locales, and URL configurations.

# Generate all URLs from Magerun and warm them
php /usr/local/bin/n98-magerun2 sys:url:list \
  --add-all-stores \
  --format=plain \
  | grep '^http' \
  | xargs -P 6 -I{} curl -s -o /dev/null \
    -H "X-Forwarded-Proto: https" \
    -A "CacheWarmer/1.0" "{}"
Enter fullscreen mode Exit fullscreen mode

This is particularly useful for multistore setups where you have multiple base URLs that may not all appear in a single sitemap.

Strategy 3: Prioritized Warming

Not all pages are equal. Your homepage, top category pages, and bestseller PDPs get 10x more traffic than the long tail. Warm high-priority pages first.

Create a warm-priority.txt with your most important URLs:

https://your-store.com/
https://your-store.com/sale.html
https://your-store.com/new-arrivals.html
https://your-store.com/men.html
https://your-store.com/women.html
https://your-store.com/brands.html
Enter fullscreen mode Exit fullscreen mode

Then in your deploy pipeline:

# Phase 1: warm critical pages immediately (sequential for reliability)
while IFS= read -r url; do
  curl -s -o /dev/null "$url"
done < warm-priority.txt

echo "Priority pages warmed. Starting full crawl in background..."

# Phase 2: warm the rest asynchronously
nohup ./warm-cache.sh &>/var/log/cache-warm.log &
Enter fullscreen mode Exit fullscreen mode

This ensures the most important pages are cached within seconds of deploy, while the full warm runs in the background.

Strategy 4: Varnish PURGE + Warm Pipeline

If you're running Varnish in front of Magento, you can build a smarter pipeline: instead of warming everything after a flush, only warm pages that were actually purged.

Magento sends PURGE requests to Varnish when cache tags are invalidated (e.g., after saving a product). You can intercept these in Varnish using a custom VCL logging hook, then re-crawl only those URLs.

sub vcl_recv {
  if (req.method == "PURGE") {
    # Log purged URLs for the re-warmer
    std.log("PURGE:" + req.url);
  }
}
Enter fullscreen mode Exit fullscreen mode

Parse the Varnish log with varnishlog and feed purged URLs to your crawler. This is advanced but dramatically reduces warming time on large stores.

Strategy 5: Magento 2 Cron-Based Warming

For stores that flush cache during maintenance windows (e.g., after a reindex), add a Magento cron job that triggers warming automatically.

Create a simple cron class in your module:

namespace Vendor\CacheWarmer\Cron;

use Magento\Framework\HTTP\Client\Curl;
use Magento\Sitemap\Model\ResourceModel\Sitemap\CollectionFactory;

class WarmCache
{
    public function __construct(
        private Curl $curl,
        private CollectionFactory $sitemapCollectionFactory
    ) {}

    public function execute(): void
    {
        $sitemaps = $this->sitemapCollectionFactory->create();
        foreach ($sitemaps as $sitemap) {
            $this->warmFromSitemap($sitemap->getSitemapUrl());
        }
    }

    private function warmFromSitemap(string $url): void
    {
        $this->curl->get($url);
        $body = $this->curl->getBody();
        preg_match_all('/<loc>([^<]+)<\/loc>/', $body, $matches);
        foreach ($matches[1] as $pageUrl) {
            $this->curl->get($pageUrl);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Register this in crontab.xml to run after peak cache-clearing operations.

Warming with Customer Context

One subtlety: Magento FPC can vary by customer group (not logged in, logged in, specific groups). By default, only the CUSTOMER_GROUP_ID=0 (guest) variant is cached via FPC. Your warmer should simulate guest requests:

curl -s -o /dev/null \
  -b "" \
  -H "X-Forwarded-Proto: https" \
  -H "Accept-Encoding: gzip" \
  "$URL"
Enter fullscreen mode Exit fullscreen mode

Avoid sending session cookies in warming requests — this will generate separate cache variations per session and negate the warming benefit.

Deploy Pipeline Integration

The ideal warming workflow integrates directly into your CI/CD pipeline. Using GitHub Actions:

- name: Warm Magento Cache
  run: |
    echo "Waiting for Varnish to propagate purges..."
    sleep 10
    chmod +x ./scripts/warm-cache.sh
    ./scripts/warm-cache.sh
  env:
    STORE_URL: ${{ secrets.STORE_URL }}
Enter fullscreen mode Exit fullscreen mode

Add this step after php bin/magento cache:flush and before removing the maintenance flag. Users won't be let in until the critical pages are already warm.

Measuring Warming Effectiveness

Track your warming success with:

# Check FPC hit rate in Magento logs
grep "cache_type.*full_page" var/log/system.log | tail -50

# Check Varnish hit rate
varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss \
  | awk '{print $1, $2}' \
  | paste - - \
  | awk '{printf "Hit rate: %.1f%%\n", $2/($2+$4)*100}'
Enter fullscreen mode Exit fullscreen mode

A well-warmed cache should hit 80–90% within 5 minutes of a deploy on a typical store.

Key Takeaways

  1. Always warm after deploy — don't let users hit the cold cache
  2. Prioritize high-traffic pages — warm them first, synchronously
  3. Use your sitemap — it's the simplest accurate source of pages to warm
  4. Set concurrency carefully — too many parallel requests can spike your backend
  5. Integrate into CI/CD — make warming automatic, not manual

Cache warming is a small operational investment with a disproportionate impact on perceived performance. Your store should feel equally fast at 2:01 AM post-deploy as it does at peak traffic — and with a solid warming strategy, it will.

Top comments (0)