Skip to content

Drupal Caching — Internal Caching, BigPipe, CDN and Performance

DodaTech Updated 2026-06-27 10 min read

In this tutorial, you'll learn how Drupal caching works — from internal page cache and BigPipe to render cache, views cache, CDN integration, and cache invalidation strategies that keep your production site fast and fresh.

What You'll Learn

  • The different cache types in Drupal and what each one does
  • How BigPipe progressively renders pages for perceived performance
  • Configuring view caching for database query optimization
  • Integrating CDN services like Cloudflare with Drupal
  • Cache invalidation strategies for content freshness

Why It Matters

Drupal is a dynamic CMS — every page request can involve dozens of database queries, plugin calculations, and render operations. Without caching, a single page can take 2-3 seconds to load. With proper caching, that same page loads in under 200 milliseconds. Caching is not optional for production Drupal sites. It directly impacts user experience, search engine rankings, server costs, and scalability. A well-cached Drupal site can handle 10 times the traffic with the same server resources.

Real-World Use

A high-traffic news website using Drupal serves 500,000 visitors per day. Page cache serves anonymous users static HTML copies of articles from Redis. BigPipe delivers authenticated user pages progressively — the main content loads first, then personalization blocks (user menu, shopping cart) load asynchronously. The CDN caches images and aggregated CSS/JS at 50 edge locations worldwide. When an editor publishes a new article, cache tags invalidate the homepage, category pages, and search index simultaneously.

Learning Path

flowchart LR
  A[Essential Modules] --> B[Caching]
  B --> C[SEO]
  C --> D[Multilingual]
  D --> E[User Roles]
  E --> F[User Management]
  F --> G[Security Hardening]

Cache Types Overview

Drupal has multiple cache layers. Understanding each one helps you configure them correctly.

  • Page cache — stores full HTML pages for anonymous users
  • Dynamic Page Cache — caches pages for authenticated users per-session fragments
  • BigPipe — sends content progressively using lazy loading
  • Render cache — caches individual rendered elements (blocks, nodes)
  • Views cache — caches query results and rendered output from Views
  • Entity cache — caches loaded entities (nodes, users, taxonomy)
  • Block cache — caches rendered block content

Internal Page Cache

The Internal Page Cache module stores complete HTML pages and serves them to anonymous users without bootstrapping Drupal fully.

# Enable the Page Cache module:
drush en page_cache

How It Works

When an anonymous user visits a page, Drupal generates the HTML and stores it. The next anonymous Visitor gets the cached HTML directly — no database queries, no module hooks, no Twig rendering.

Configuration

# Performance settings for page cache:
page_cache:
  max_age: 21600  # 6 hours in seconds

Go to Configuration > Development > Performance to set:

  • Page cache max age — how long browsers can cache the page
  • Cache pages for anonymous users — enable/disable

Limitations

Page cache works only for anonymous users. Authenticated users get personalized content (user menu, contextual links) that cannot be fully cached.

Dynamic Page Cache

The Dynamic Page Cache module extends caching to authenticated users. It caches everything except personalized fragments.

# Enable Dynamic Page Cache:
drush en dynamic_page_cache

How It Works

Drupal renders the page and caches the entire output except for placeholders. Placeholders represent personalized content that differs per user. When a request comes in, Drupal serves the cached page and fills in the placeholders with user-specific content.

# Dynamic page cache configuration:
dynamic_page_cache:
  max_age: 3600  # 1 hour

BigPipe

BigPipe is a technique developed by Facebook for progressive page rendering. Drupal's BigPipe module sends the page shell immediately, then streams content blocks one by one.

# Enable BigPipe:
drush en big_pipe

How It Works

When a page is requested, Drupal sends the main HTML structure (page shell) immediately. Content blocks that are cacheable and not user-specific are included in this initial response. Blocks that depend on user context (user menu, cart, personalized recommendations) are replaced with placeholders. After the initial HTML is sent, Drupal sends each placeholder's content through additional HTTP responses using JavaScript.

<!-- Initial HTML contains placeholders -->
<div id="big-pipe-placeholder-1">
  <!-- User menu loads here -->
</div>
<script>
  // BigPipe JavaScript progressively fills placeholders
  big_pipe.fillPlaceholder('big-pipe-placeholder-1', '/big_pipe/session/1');
</script>

When to Use BigPipe

BigPipe benefits authenticated users who see personalized blocks. It is especially valuable for complex pages with many dynamic elements like dashboards or community sites.

Render Cache

The render cache stores the rendered output of individual elements. When a block or entity is rendered, the result is cached by cache tags, contexts, and max-age.

# Render cache configuration:
render_cache:
  max_age: -1  # -1 means permanent until invalidated

Render cache works per-element:

  • A node's rendered HTML is cached by cache tag node:123
  • A block's rendered HTML is cached by cache tag block:my_block
  • Cache contexts like url, user, and language create separate cache entries per variation

Cache Tags

Every entity in Drupal has cache tags. When an entity is updated, all cached content containing that entity is invalidated.

<?php
// Cache tags are automatically set by Drupal:
$build['#cache']['tags'] = [
  'node:123',          // Specific node
  'node_list',         // List of all nodes
  'config:views.view.my_view',  // View configuration
  'taxonomy_term:5',   // Specific taxonomy term
];

// You can add custom cache tags:
$build['#cache']['tags'][] = 'my_custom_tag';

When node 123 is updated:

<?php
// Drupal automatically invalidates all caches with tag 'node:123'
Cache::invalidateTags(['node:123']);

This means the homepage (which lists node 123), the node page itself, and any block showing node 123 are all invalidated simultaneously.

Cache Contexts

Cache contexts define variations of cached content. Each context creates a separate cache entry.

<?php
// Cache contexts create separate cache entries per variation:
$build['#cache']['contexts'] = [
  'url',          // Different URL = different cache entry
  'user',         // Per-user cache entry
  'user.roles',   // Per-role cache entry
  'language',     // Per-language entry
  'timezone',     // Per-timezone entry
  'cookies:my_cookie',  // Based on a cookie value
  'headers:X-My-Header', // Based on a request header
  'route',        // Per-route entry
];

Choose the minimum set of contexts needed. Each context multiplies cache entries. Adding user context creates a separate cache entry for every user, which defeats caching on high-traffic sites.

Cache Max-Age

Max-age defines how long a cached element is valid. When the max-age expires, the content is re-rendered.

<?php
// Cache max-age settings:
$build['#cache']['max-age'] = 3600;         // 1 hour
$build['#cache']['max-age'] = 86400;        // 1 day
$build['#cache']['max-age'] = -1;            // Permanent (until tag invalidation)
$build['#cache']['max-age'] = 0;             // Never cache

Views Caching

Views has its own caching layer with two levels: query results and rendered output.

  1. Go to Structure > Views > Edit your view
  2. Click on the display (e.g., Page, Block)
  3. Click "Caching" in the advanced settings
# Views caching configuration:
cache:
  type: time
  results:
    lifetime: 3600     # Cache query results for 1 hour
  output:
    lifetime: 3600     # Cache rendered output for 1 hour

Query Results Cache

Caches the SQL query result. Useful for views that perform complex joins or aggregations.

Rendered Output Cache

Caches the fully rendered HTML of the view output. More aggressive caching.

# Aggressive views caching with tag-based invalidation:
cache:
  type: tag
  results:
    lifetime: 3600
  output:
    lifetime: 3600

CDN Integration

A CDN (Content Delivery Network) caches your site's static assets at edge locations worldwide.

Cloudflare

  1. Enable the Cloudflare module:
composer require drupal/cloudflare
drush en cloudflare
  1. Configure Cloudflare API credentials
  2. Set caching rules for static assets
  3. Enable "Automatic HTTPS Rewrites"
# Cloudflare module configuration:
cloudflare:
  apikey: 'your_api_key'
  email: 'your_email@example.com'
  zone_id: 'your_zone_id'

Fastly

For enterprise setups:

composer require drupal/fastly
drush en fastly

Cache Invalidation

The Purge module manages cache invalidation across CDNs:

composer require drupal/purge drupal/purge_drush
drush en purge purge_drush
# Invalidate CDN cache for specific URLs:
drush purge-invalidate 'node:123'
drush purge-invalidate 'http://example.com/node/123'

Varnish

Varnish is an HTTP cache accelerator that sits in front of Drupal.

# Install Varnish (on server):
sudo apt install varnish

Varnish configuration for Drupal (/etc/varnish/default.vcl):

sub vcl_recv {
  # Pass through admin paths
  if (req.url ~ "^/admin" || req.url ~ "^/user") {
    return (pass);
  }
  
  # Remove cookies for anonymous users
  if (req.http.cookie ~ "SESS") {
    return (pass);
  }
  
  # Cache static assets aggressively
  if (req.url ~ "\.(css|js|png|jpg|jpeg|gif|ico|svg)$") {
    unset req.http.cookie;
    return (hash);
  }
}

sub vcl_backend_response {
  # Set cache TTL
  set beresp.ttl = 1h;
  
  # Cache tagged content
  if (beresp.http.X-Drupal-Cache-Tags) {
    set beresp.ttl = 2h;
  }
}

Cache Metadata Best Practices

Always set cache tags on custom render arrays so they invalidate properly. Use the minimum number of cache contexts to avoid cache fragmentation. Set reasonable max-age values — not everything needs permanent caching. Use tag-based invalidation instead of time-based expiration where possible. Monitor cache hit rates to verify your caching Strategy is working. Test cache invalidation by updating content and verifying the changes appear immediately.

Common Mistakes

  1. Not enabling Dynamic Page Cache for authenticated users: Authenticated users get no caching benefits without the Dynamic Page Cache module, causing poor performance for logged-in traffic.

  2. Excessive cache contexts: Adding user context to everything creates separate cache entries for every user, negating caching benefits. Use user.roles instead of user when possible.

  3. Not setting cache tags on custom blocks: Custom blocks without cache tags are never invalidated when content changes. Add the appropriate entity cache tags to your block's render array.

  4. Disabling caching during development and forgetting to re-enable: Production sites with caching disabled perform terribly. Always verify cache settings before launch.

  5. Not clearing caches after configuration changes: Configuration changes have their own cache tags, but some settings require a manual drush cr to take effect.

Practice Questions

  1. How does BigPipe improve perceived performance compared to traditional synchronous page loading?

  2. What is the difference between cache tags, cache contexts, and cache max-age? Give an example of each.

  3. How would you configure Views caching for a listing page that updates hourly but must reflect content changes immediately?

  4. Challenge: Design a caching strategy for a community forum site with anonymous visitors, registered members, and moderators. Define which cache types to use for each user group, how to handle personalized blocks (user menu, notifications), what CDN setup to use, and how cache invalidation works when a moderator edits a post.

FAQ

What is BigPipe in Drupal?

BigPipe is a caching technique that sends the main page HTML immediately, then progressively loads personalized content blocks asynchronously. It improves perceived load time for authenticated users by rendering cacheable content first.

How do I clear Drupal's cache?

Use drush cr to clear all caches. You can also clear individual cache bins with drush cache:clear render or go to Configuration > Development > Performance and click 'Clear all caches.'

What is the difference between Page Cache and Dynamic Page Cache?

Page Cache stores full HTML for anonymous users only. Dynamic Page Cache caches pages for authenticated users, replacing personalized sections with placeholders that are filled per-request.

How does CDN caching work with Drupal?

A CDN caches static assets (CSS, JS, images) at edge locations. The Purge module integrates with CDNs to invalidate cached content when it changes. Cloudflare and Fastly have dedicated Drupal modules.

What are cache tags in Drupal?

Cache tags are identifiers attached to cached content that reference the entities used to build it. When an entity is updated, all cache entries with its tag are invalidated, ensuring fresh content is served.

Mini Project

Goal: Configure and test a multi-layer caching setup.

  1. Enable Internal Page Cache and Dynamic Page Cache modules
  2. Configure page cache max age to 6 hours in Performance settings
  3. Enable BigPipe module for authenticated users
  4. Create a View with tag-based caching
  5. Add cache tags to a custom block in a preprocess function
  6. Install and configure the Purge module with a CDN (Cloudflare or Fastly)
  7. Test anonymous page load speed before and after caching
  8. Update a node and verify cache invalidation works
  9. Monitor cache hit rate using the web profiler from Devel

What's Next

Now that you understand caching, proceed to Drupal SEO to learn about search engine optimization with Metatag, XML Sitemap, and Schema.org. After that, explore multilingual Drupal for international sites.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro