---
title: "How does Drupal page cache work?"
date: "2025-02-05T23:17:09+00:00"
summary: "Discover how Drupal page caching works, its storage mechanisms, and clearing methods. Optimize your site's performance."
image:
type: "article"
url: "/acquia-cloud-platform/help/93426-how-does-drupal-page-cache-work"
id: "34500bee-4375-4e9d-bec7-8fe6cf534a36"
---

Drupal page caching keeps copies of the fully rendered HTML for a page; this can include content, views, images, and so on. When you troubleshoot issues with caching, understanding how Drupal handles the page cache can help you narrow down the problem more quickly.

A deep dive into the bootstrap and page caching process is covered in [Digging Deeper into Drupal Page Caching](https://bkosborne.com/blog/digging-deeper-into-drupal-page-caching).

### What's stored, and how?

Drupal's page cache stores the fully rendered HTML of each page that is required to cache. It does this using a Cache ID (`cid`) that corresponds to the actual URL used to request the page. This is similar to how Varnish identifies what to cache.

As the URL is the `cid`, URIs that map to the same logic are cached as different items in the Drupal page cache. For example, if your front page is actually mapped to `/node`, these are content-equivalent but are cached as separate items. For example, these URIs are functionally equivalent, but are stored separately:

*   [http://example.com/](http://example.com/)
*   [http://example.com/?cachebust](http://example.com/?cachebust)
*   [http://example.com/node](http://example.com/node)
*   [http://example.com/node?cachebust](http://example.com/node?cachebust)

The following code snippet returns a portion of the cached data from the page cache, regardless of the database storage mechanism:

    drush ev '$uri = "http://example.com/"; $x = cache_get($uri, "cache_page"); if ($x) { $body = gzinflate(substr(substr($x->data['body'], 10), 0, -8)); $x->data["body"] = substr($body, 0, 512) . " [... snip!]\n"; foreach (array("created", "expire") as $element) { if ($x->$element) { $x->$element .= " [" . strftime("%c", $x->$element) . "] == " . ($x->$element - time()) . " secs from now"; } }  print_r($x); } else { echo "No data found!\n"; }'

This alternative snippet displays the metadata about a cached page, or tells you that there was no matching cache entry, but does not display the actual content:

    drush ev '$uri = "http://example.com/page"; $cached_page = cache_get($uri, "cache_page"); $cached_page->data['body'] = "BODY"; if (is_numeric($cached_page->created)) { $cached_page->created_h = date('r', $cached_page->created); $cached_page->expire_h = date('r', $cached_page->expire); } else { $cached_page = "no cache entry\n"; } print_r($cached_page);';

Here's an example of what you might get in return:

    stdClass Object(    [cid] => http://example.com/page    [data] => Array        (            [path] => page            [body] => BODY            [title] => Page not found            [headers] => Array                (                    [Content-Type] => text/html; charset=utf-8                    [Content-Language] => en                    [Status] => 404 Not Found                    [X-UA-Compatible] => IE=edge,chrome=1                    [X-Generator] => Drupal 7 (http://drupal.org)                )             [page_compressed] => 1        )     [created] => 1402494021    [expire] => -1    [serialized] => 1    [created_h] => Wed, 11 Jun 2014 07:40:21 -0600    [expire_h] => Wed, 31 Dec 1969 16:59:59 -0700)

If the output page has messages (output by `drupal_set_message()`), this page is not stored in page cache during this request.

The `X-Drupal-Cache` header can also be added to responses, and you may see these in the `Array`:

*   `X-Drupal-Cache: MISS` for pages not served from cache display.
*   `X-Drupal-Cache: HIT` for pages served from cache.

For more details on these messages, visit [function \_drupal\_bootstrap\_page\_cache](https://api.drupal.org/api/drupal/includes!bootstrap.inc/function/_drupal_bootstrap_page_cache/7) .

### Clearing items from the Drupal page cache

Similar to any other cache clearing mechanism, clearing items from the Drupal page cache is dependent on several variables.

*   Each item in the page cache might have different expiry times, after which, it is purged from the Drupal page cache or ignored.
*   Some operations purge every stale (or expired) item from the page cache.
*   The `expire` property on the cache object tells you when a particular item expires.
*   The Drupal page cache normally tags each Page cache item with the `CACHE_TEMPORARY` constant (internally, -1) to know when the item expires.

### Core database caching versus Memcache

Differences between page cache in Drupal core cache and `memcache.inc`

 

Drupal core caching

Memcache

How items are tagged for expiration

Items are tagged with `expire = CACHE_TEMPORARY (-1)`

Instead of tagging items with `CACHE_TEMPORARY`, it sets expiry to a specific time, one month in the future.

Actions and API calls that clear out items from the page cache

*   Calling `cache_clear_all(NULL, "cache_page");`
*   Running `drush cc all`
*   Calling `system_cron()` (which is included in the normal `cron.php` or `drush cron` runs).
*   Editing or creating any single node through the user interface
*   Editing a View.
*   Enabling or disabling a module.

*   Calling `cache_clear_all(NULL, "cache_page");`
*   Running `drush cc all`

For more information, visit [Temporary cache is not being flushed on cron run causing issues with cache\_form stored in database](https://drupal.org/node/1634506).

Note

Drupal core purges items from the cache that are older than the `cache_lifetime`. This setting is set by the [Minimum cache lifetime](/node/56424).

### How does Minimum cache lifetime work?

The minimum cache lifetime is equivalent to setting the `cache_lifetime` Drupal variable. It prevents Drupal from clearing page and block caches after changes are made to nodes or blocks, for a set period of time. This can cause unexpected behavior when editing content or when an external cache such as Varnish is employed. Minimum cache lifetime should be used with caution. If you are unsure, set [minimum cache lifetime set](/node/56424) to 0.

If you are self-hosted, you can run into a situation where not all caching clears upon `node_update`. This can be because of the differences with memcache, noted previously. In this particular example, a customer was instructed to create a custom module to force a [`cache_clear_all`](https://api.drupal.org/api/drupal/includes%21cache.inc/function/cache_clear_all/7.x) on the home page after a [`node_update`](https://api.drupal.org/api/drupal/modules%21node%21node.api.php/function/hook_node_update/7.x), which wipes out the page cache in memcache:

Note

The following code is applicable for only Drupal 7:

    function mymodule_node_update($node) { if ($node->type == 'emergency_update') {  $url = url('<front>', array('absolute' => TRUE));  cache_clear_all($url, 'cache_page'); }}

For more information, visit [Varnish cache HITS and Drupal cache MISS](/node/92591).