Skip to content
Gaurav TiwariDocs

Warm the Cache After a Purge

Version 1.3.6 Updated October 26, 2026

After a full purge every page is cold, and the first visitor to each one pays for the render. A warm run rebuilds pages in the background from your sitemaps, most recently changed first, and records for every URL whether the origin actually stored a page.

Warming exists to fill GT Performance’s own page store, so it does not run in optimize-only mode, where the host’s cache stores pages instead. No warm run is queued after a full purge, the stale-page refresh is skipped, and Start warm run and wp gt-performance cache warm refuse with a message that nothing was queued.

Starting a run

A run starts:

  • Automatically after a full purge, when the page cache and Warm cache after a full purge are both on. The run is queued 30 seconds later, and a burst of full purges (a theme switch plus a menu save) within a minute queues one run, not several.
  • From Tools > Cache warming > Start warm run.
  • From WP-CLI:
wp gt-performance cache warm
wp gt-performance queue run          # process it now instead of waiting for cron
wp gt-performance cache warm-status

To rebuild a single page, use Warm this URL in the admin bar. See Purging.

Starting a run while another is unfinished marks the earlier one superseded. Its already-queued preloads still run, but their results no longer count against it.

Where URLs come from

Page Cache > Cache warming > Sitemap sources (cache.preload_sitemaps) takes up to 10 sitemap URLs from this site, one per line. When it is empty, the run uses:

  1. the WordPress core sitemap, /wp-sitemap.xml
  2. every Sitemap: line in /robots.txt, which is where SEO plugins announce their own sitemaps

Only sources on the same scheme, host and port as the home URL are used, and at most 10 in total. The home page is always warmed first.

Discovery rules:

  • Each discovery job fetches at most two sitemaps, so a large site is read across many short background jobs instead of one long request.
  • Sitemap indexes are followed up to five levels deep.
  • Redirects are not followed automatically. Each hop is recorded as its own target, must stay on this site, and counts as a level.
  • A sitemap response is read up to 2 MB, robots.txt up to 64 KB. A truncated sitemap is reported.
  • Entries on other domains are skipped and reported.
  • URLs the cache would bypass anyway (a bypass path, an unknown query parameter, and so on) are never queued.
  • A run holds at most 50,000 targets, sitemaps and variants included.

Progress lives in the gtperf_warm_targets table, so a worker that dies mid-run resumes where it stopped. Every target is identified by its normalized URL, so a sitemap that lists itself, or a cycle of indexes, is fetched once.

Recent pages first

Each sitemap entry is ranked by its <lastmod>:

PriorityTargets
FirstThe home page
NextEntries modified in the last 7 days
ThenEverything else, including entries without a <lastmod>

With Separate cache for mobile HTML on, every URL gets a second target for the mobile variant, requested with a phone user agent.

Batches

Warming dispatches URLs per warming batch (cache.preload_max_urls, default 200, maximum 2,000) preload jobs at a time, then waits for all of them to report before queuing the next batch. It checks once a minute. After 30 checks without a result, the missing ones are marked failed with no_result and the run carries a lost_results warning instead of waiting forever. Cancelled or lost preload jobs are the usual cause.

Set the batch size to 0, or turn Warm cache after a full purge off, to stop rebuilding without turning caching off. A run that reaches dispatch in that state skips its remaining URLs as preload_disabled and ends partial.

Warm jobs run at the same priority as ordinary preloads, ahead of unused-CSS generation. Pausing optional queue work pauses warming too. See Tools.

Cache size budget

A run never warms more pages than the cache is allowed to keep. Each batch is capped by the room left under cache.entry_budget (default 5,000 entries, 0 for no limit), counting every URL target this run has already queued or reported. When the budget is used up, the remaining URLs are skipped as capacity_limited and the run ends in the capacity_limited state. Because the home page and recently changed pages go first, those are the ones a budget smaller than the site keeps.

The same budget drives eviction in the hourly garbage collector. See Page Cache for how to change it.

Per-page results

A 200 response is not proof of a warm cache. Each preload is classified from the evidence:

ResultDetailMeaning
origin_readyrebuiltThe origin stored a fresh page during this request
origin_readyexistingA fresh origin entry was already there
edge_observedcf_hit, cf_stale, cf_updating, cf_revalidatedCloudflare answered from its cache and no fresh origin entry exists
requestedno_artifact, or gt_<status>HTTP 200, but nothing was stored. The detail carries the X-GT-Cache value when there was one
skippeda bypass reason, or invalid_urlThe URL is not cacheable, so it was never requested
skippedredirect_<code> (for example redirect_301), http_<code> for a 4xx (for example http_404)The page answered with a redirect or a client error. That is the page’s answer, not a hiccup, so it is not retried
failedhttp_<code> for a 5xx or any other non-200 status, request_error, no_resultA server error, a transport error, or no report

Preload requests carry a signed X-GT-Preload token (an HMAC derived from AUTH_KEY, valid for ten minutes), do not follow redirects, time out after 15 seconds, and identify themselves as GT-Performance-Preloader/<version>. The token is what lets a preload rebuild a stale page; the drop-in ignores the header without a valid one. A failed preload job (a server error or a transport failure) is retried with backoff, up to three attempts in total. A redirect or a 4xx is recorded as skipped at once: a sitemap that still lists a moved post gets the same 301 on every retry.

Run states and warnings

StateMeaning
discoveringReading sitemaps
warmingDispatching preload batches
completeEvery sitemap read and every URL reported
partialFinished with a sitemap failure or one of the warnings below
capacity_limitedStopped at the cache size budget
supersededReplaced by a newer run

Warnings recorded on a run: sitemap_failed, sitemap_truncated, sitemap_skipped (a redirect left the site or went too deep), depth_limit, target_cap, foreign_entries, lost_results, preload_disabled. Any of sitemap_truncated, depth_limit, target_cap, sitemap_skipped or lost_results, or a failed sitemap, makes the run partial.

Where to see it

Tools > Cache warming shows the latest run: state, origin ready, edge only, waiting, failed, plus how many URLs answered without a stored page, how many were skipped, how many sitemaps were read or failed, when it last changed, and its warnings.

wp gt-performance cache warm-status prints the state, the sources (as paths), the warnings and every target count by kind and status.

The health report (Tools, Site Health, wp gt-performance health) includes the latest run and warns when it is partial, capacity_limited, has failed URLs, or has made no progress for 30 minutes while still running. See Diagnostics.

Target rows are kept for 7 days and the last 10 run summaries are kept in the gt_performance_warm_runs option.

Settings

LabelKeyDefault
Warm cache after a full purgecache.preloadOn
URLs per warming batchcache.preload_max_urls200 (0 to 2,000)
Sitemap sourcescache.preload_sitemapsEmpty (WordPress sitemap plus robots.txt)
Cache size budget (no admin field)cache.entry_budget5,000

Warm cache after a full purge also gates the stale-revalidation sweep described on Page Cache. Preloads queued after a publish or update run regardless of it.

AI assistants with operate permission can queue preloads for up to 20 URLs through the gt-performance/preload-urls ability. See AI and MCP.

Share

Was this helpful?

Still stuck? Open a support ticket