PerformanceUpdated Feb 2026

    Website Caching Explained: From Browser Cache to Redis

    Caching is the single biggest performance win for most websites. A properly cached WordPress site serves pages in 30ms instead of 800ms. This guide covers every caching layer, what it does, how to configure it, and when to use it.

    Mallory Keegan
    Mallory Keegan

    Web hosting enthusiast who tests providers and breaks down features, pricing, and real world speed

    Website caching layers diagram showing browser cache, CDN edge cache, server-side page cache, OPcache, Redis object cache, and database query cache
    Every caching layer explained: from browser cache to Redis object caching

    Impact at a Glance

    Caching LayerSpeed GainDifficultyCost
    Browser Cache50–80% fewer requestsEasyFree
    CDN Cache30–70% faster globallyEasyFree: $20/mo
    Full-Page Cache10–20x faster TTFBEasyFree
    OPcache2–3x faster PHPEasyFree
    Redis Object Cache30–50% faster uncachedMedium$0–10/mo
    DB Query Cache10–20% faster queriesAdvancedFree

    What Is Caching?

    Caching stores a copy of data in a faster-to-access location so future requests can be served without repeating expensive operations. Instead of executing PHP code, querying a database, and assembling HTML on every page view, a cache serves a pre-built result in milliseconds.

    Without caching, every visitor triggers the full processing pipeline: DNS lookup → TCP connection → PHP execution → database queries → HTML generation → response. With caching, most of this work is skipped entirely.

    MetricNo CachingFull Caching Stack
    TTFB300–2,000 ms20–50 ms
    Full Page Load2–8 seconds0.5–1.5 seconds
    Database Queries/Page30–2000 (served from cache)
    PHP Execution Time200–800 ms0 ms (bypassed)
    Server CPU Per RequestHighMinimal
    Max Concurrent Users (2GB VPS)50–100500–2,000
    Monthly Bandwidth100%30–50% (CDN offloads)

    The 6 Caching Layers

    A complete caching strategy uses multiple layers, each targeting a different part of the request lifecycle. Here's the order a request passes through, from closest to the user to closest to the database.

    1

    Browser Cache

    Stores static files (CSS, JS, images) on the user's device. Eliminates network requests for returning visitors.

    2

    CDN Cache

    Caches content on edge servers worldwide. Reduces latency by serving from the nearest location. Handles 60–90% of static requests.

    3

    Full-Page Cache

    Stores complete HTML pages on the server. Bypasses PHP and database entirely. The single biggest speed win.

    4

    OPcache

    Caches compiled PHP bytecode in memory. Eliminates re-parsing PHP files on every request. Built into PHP.

    5

    Object Cache (Redis)

    Stores database query results and computed objects in RAM. Reduces database load by 50–90% for dynamic pages.

    6

    Database Query Cache

    MySQL/MariaDB caches identical query results. Lowest-level cache, often superseded by Redis.

    Browser Cache

    Browser caching tells the visitor's browser to store static files locally. On subsequent visits, the browser loads CSS, JavaScript, images, and fonts from disk instead of downloading them again. This eliminates 50–80% of network requests for returning visitors.

    Nginx, recommended cache headers

    # /etc/nginx/conf.d/cache-headers.conf
    
    # Static assets, cache for 1 year (they use hashed filenames)
    location ~* \.(css|js|woff2|woff|ttf|eot)$ {
        expires 365d;
        add_header Cache-Control "public, immutable";
        add_header Vary "Accept-Encoding";
    }
    
    # Images, cache for 6 months
    location ~* \.(jpg|jpeg|png|gif|webp|avif|svg|ico)$ {
        expires 180d;
        add_header Cache-Control "public";
    }
    
    # HTML, short cache with revalidation
    location ~* \.html$ {
        expires 1h;
        add_header Cache-Control "public, must-revalidate";
    }
    
    # API responses, no cache
    location /api/ {
        add_header Cache-Control "no-store, no-cache, must-revalidate";
    }

    Apache, .htaccess cache rules

    <IfModule mod_expires.c>
      ExpiresActive On
      ExpiresByType text/css "access plus 1 year"
      ExpiresByType application/javascript "access plus 1 year"
      ExpiresByType image/webp "access plus 6 months"
      ExpiresByType image/jpeg "access plus 6 months"
      ExpiresByType image/png "access plus 6 months"
      ExpiresByType font/woff2 "access plus 1 year"
      ExpiresByType text/html "access plus 1 hour"
    </IfModule>
    
    <IfModule mod_headers.c>
      # Immutable for hashed assets
      <FilesMatch "\.(css|js|woff2)$">
        Header set Cache-Control "public, immutable, max-age=31536000"
      </FilesMatch>
    </IfModule>
    HeaderPurposeExample
    Cache-ControlPrimary directive for caching behaviorpublic, max-age=31536000, immutable
    ExpiresLegacy fallback (HTTP/1.0)Thu, 01 Jan 2027 00:00:00 GMT
    ETagFingerprint for conditional requests"5d8c72a5edda8"
    Last-ModifiedTimestamp for conditional requestsMon, 15 Jul 2026 12:00:00 GMT
    VaryCache key modifiersAccept-Encoding

    CDN Cache

    A Content Delivery Network caches your content on edge servers in 100+ locations worldwide. Instead of every visitor hitting your origin server, 60–90% of requests are served from the nearest edge node, reducing latency from 200ms to 20ms for distant visitors.

    CDN ProviderEdge LocationsFree TierFull-Page CacheBest For
    Cloudflare310+Yes (generous)Yes (Page Rules)Most websites
    Bunny CDN116+14-day trialYes (Perma-Cache)Budget-conscious
    AWS CloudFront450+1TB/mo free (12 mo)Yes (behaviors)AWS-hosted apps
    Fastly90+NoYes (VCL)Enterprise / real-time
    KeyCDN60+NoLimitedSimple static sites

    Pro tip: Cloudflare's free tier with APO (Automatic Platform Optimization, $5/mo) caches entire WordPress pages on the edge, turning every page load into a CDN cache hit. It's the single easiest performance upgrade for WordPress sites.

    Full-Page Cache

    Full-page caching stores the complete HTML output of a page so subsequent requests skip PHP execution and database queries entirely. This is the most impactful single optimization for dynamic sites, reducing TTFB from 300–800ms to 20–50ms.

    Nginx FastCGI Cache, server-level page caching

    # In nginx.conf (http block)
    fastcgi_cache_path /var/cache/nginx levels=1:2
      keys_zone=WORDPRESS:100m inactive=60m max_size=1g;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    
    # In your server block
    set $skip_cache 0;
    
    # Don't cache POST requests
    if ($request_method = POST) { set $skip_cache 1; }
    
    # Don't cache URLs with query strings
    if ($query_string != "") { set $skip_cache 1; }
    
    # Don't cache logged-in users
    if ($http_cookie ~* "wordpress_logged_in") { set $skip_cache 1; }
    
    # Don't cache WooCommerce pages
    if ($request_uri ~* "/cart|/checkout|/my-account") { set $skip_cache 1; }
    
    location ~ \.php$ {
        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 60m;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
        add_header X-FastCGI-Cache $upstream_cache_status;
        # ... standard PHP-FPM config
    }
    MethodSpeedComplexityBest For
    Nginx FastCGI CacheFastest (10–20ms TTFB)Medium (server config)VPS / dedicated servers
    LiteSpeed Cache (LSAPI)Very fast (15–25ms TTFB)Easy (plugin)LiteSpeed servers
    Varnish Reverse ProxyVery fast (10–20ms TTFB)High (VCL config)High-traffic sites
    WP Super Cache (plugin)Fast (30–50ms TTFB)Very easyShared hosting / beginners
    W3 Total Cache (plugin)Fast (30–50ms TTFB)Medium (many options)Advanced WordPress users
    WP Rocket (plugin)Fast (25–40ms TTFB)Very easyWordPress (paid, $59/yr)

    Opcode Cache (OPcache)

    Every time PHP processes a file, it parses the source code into bytecode, then executes it. OPcache stores the compiled bytecode in shared memory, eliminating the parsing step on every request. This gives a 2–3x PHP execution speed improvement with zero code changes.

    Recommended OPcache settings (php.ini)

    ; Enable OPcache
    opcache.enable=1
    opcache.enable_cli=0
    
    ; Memory, 256MB handles most WordPress sites + plugins
    opcache.memory_consumption=256
    
    ; Max cached files (WordPress + plugins typically need 10,000+)
    opcache.max_accelerated_files=20000
    
    ; How often to check for file changes (seconds)
    ; Production: 60+ (files rarely change)
    ; Development: 0 (check every request)
    opcache.revalidate_freq=60
    
    ; Don't waste memory on comments (unless using annotations)
    opcache.save_comments=1
    
    ; Huge pages (if supported by your OS)
    opcache.huge_code_pages=1
    
    ; Preloading (PHP 8.0+), loads framework files at startup
    ; opcache.preload=/var/www/html/preload.php
    ; opcache.preload_user=www-data

    Check OPcache status

    # Check if OPcache is enabled
    php -i | grep opcache.enable
    
    # View detailed stats (create a PHP file)
    <?php
    $status = opcache_get_status();
    echo "Memory used: " . round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . " MB\n";
    echo "Hit rate: " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%\n";
    echo "Cached files: " . $status['opcache_statistics']['num_cached_scripts'] . "\n";

    Object Cache: Redis vs Memcached

    Object caching stores the results of expensive database queries and computed data in RAM. Instead of re-running the same SQL queries on every page load, the application checks Redis/Memcached first. This reduces database load by 50–90% and speeds up uncached page generation by 30–50%.

    FeatureRedisMemcached
    Data TypesStrings, lists, sets, hashes, sorted setsStrings only
    PersistenceYes (RDB + AOF)No (RAM only)
    Max Value Size512 MB1 MB
    ReplicationBuilt-in (master-replica)No
    Pub/SubYesNo
    Lua ScriptingYesNo
    Memory EfficiencySlightly higher overheadLower per-key overhead
    Multi-threadingSingle-threaded (io-threads in 6.0+)Multi-threaded
    Best ForWordPress, Laravel, DjangoSimple key-value caching
    WordPress PluginRedis Object Cache (free)Memcached plugin

    Install Redis and connect to WordPress

    # Install Redis
    sudo apt install redis-server -y
    
    # Secure Redis, bind to localhost only
    sudo nano /etc/redis/redis.conf
    # Set: bind 127.0.0.1 ::1
    # Set: maxmemory 128mb
    # Set: maxmemory-policy allkeys-lru
    
    # Start and enable
    sudo systemctl enable redis-server
    sudo systemctl start redis-server
    
    # Test connection
    redis-cli ping  # Should return PONG
    
    # Add to wp-config.php (before "That's all, stop editing!")
    define('WP_REDIS_HOST', '127.0.0.1');
    define('WP_REDIS_PORT', 6379);
    define('WP_REDIS_DATABASE', 0);
    define('WP_REDIS_TIMEOUT', 1);
    define('WP_REDIS_READ_TIMEOUT', 1);
    
    # Then install "Redis Object Cache" plugin and click "Enable Object Cache"

    Database Query Cache

    MySQL's built-in query cache stored identical query results and returned them without re-executing. However, MySQL 8.0 removed the query cache because it caused contention under high concurrency. MariaDB still supports it.

    Modern Alternatives to MySQL Query Cache

    • Redis object cache: caches query results at the application layer with fine-grained TTL control
    • ProxySQL: query caching reverse proxy with regex-based rules and connection pooling
    • InnoDB buffer pool: increase size to cache hot data pages in memory (set to 70–80% of available RAM)
    • MariaDB query cache: still available on MariaDB 10.x with improved invalidation

    Tune InnoDB buffer pool (MySQL/MariaDB)

    # Check current buffer pool size
    mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
    
    # Set to 70-80% of available RAM (for dedicated DB server)
    # In /etc/mysql/mysql.conf.d/mysqld.cnf:
    innodb_buffer_pool_size = 1G    # For 2GB RAM server
    innodb_buffer_pool_instances = 1 # 1 per GB (up to 8)
    innodb_log_file_size = 256M
    
    # Check buffer pool hit ratio (should be >99%)
    mysql -e "SHOW STATUS LIKE 'Innodb_buffer_pool_read%';"
    # Hit ratio = 1 - (reads / read_requests) * 100

    Cache Invalidation Strategies

    "There are only two hard things in Computer Science: cache invalidation and naming things.": Phil Karlton. Serving stale content is worse than serving slow content. Here are the proven strategies:

    StrategyHow It WorksBest For
    Time-Based (TTL)Cache expires after a set duration (e.g., 60 minutes)Blog posts, static pages
    Event-Based PurgeCache cleared when content is updated (post save, product update)CMS content, eCommerce
    Cache Tags / GroupsTag cached items by category, purge all items with a specific tagComplex applications
    Stale-While-RevalidateServe stale cache while fetching fresh content in backgroundHigh-traffic APIs
    Cache Busting (versioned URLs)Append hash to filename (style.abc123.css), new file = new cacheCSS, JS, images
    Surrogate Keys (CDN)Tag CDN cache entries, purge by key via APIFastly, Cloudflare Enterprise

    WordPress Caching: Complete Setup

    WordPress benefits enormously from caching because it runs PHP and queries MySQL on every page load by default. Here's the recommended caching stack in priority order:

    PriorityLayerRecommended ToolImpact
    1Page CacheWP Rocket ($59/yr) or LiteSpeed Cache (free)10–20x TTFB reduction
    2CDNCloudflare (free) + APO ($5/mo)30–70% faster globally
    3OPcacheBuilt-in (verify enabled)2–3x PHP execution
    4Object CacheRedis + Redis Object Cache plugin (free)30–50% fewer DB queries
    5Image OptimizationShortPixel or Imagify40–70% smaller images
    6Browser CachingSet via .htaccess or hosting panel50–80% fewer requests

    Don't stack multiple page caching plugins. Using WP Super Cache + W3 Total Cache + WP Rocket together causes conflicts, double-caching, and broken pages. Pick one page cache plugin and stick with it.

    Hosting Provider Caching Support

    Many managed hosts include built-in caching, saving you from configuring it yourself. Here's what each provider offers out of the box.

    ProviderPage CacheCDNRedisOPcache
    KinstaNginx FastCGICloudflare EnterpriseYes (all plans)Yes
    CloudwaysVarnish + BreezeCloudflare (add-on)Yes (1-click)Yes
    SiteGroundSuperCacher (Nginx)Cloudflare (free)Yes (GoGeek+)Yes
    WP EngineEverCache (proprietary)Global CDN includedYes (custom)Yes
    HostingerLiteSpeed CacheCloudflare (built-in)No (shared)Yes
    A2 HostingLiteSpeed / TurboCloudflare (free)Yes (Turbo plans)Yes
    DigitalOcean (DIY)Manual setupManual setupManual setupManual
    BluehostPlugin-basedCloudflare (built-in)NoYes

    Common Caching Mistakes

    ❌ Caching logged-in user pages

    ✅ Always exclude logged-in users from page cache. Cached user-specific content (cart, dashboard) can leak to other visitors, a serious privacy issue.

    ❌ Stacking multiple page cache plugins

    ✅ Use only ONE page caching solution. Multiple plugins create conflicting cache files, doubled memory usage, and broken invalidation.

    ❌ Setting OPcache revalidation to 0 in production

    ✅ In production, set opcache.revalidate_freq=60 or higher. Checking for file changes on every request defeats the purpose.

    ❌ Not purging cache after updates

    ✅ Configure automatic cache purging on post save, theme update, and plugin update. Stale cache = stale content = confused visitors.

    ❌ Caching 404 pages and error responses

    ✅ Only cache 200 OK responses. Caching 404s can prevent new content from appearing after publishing.

    ❌ Using Redis without maxmemory or eviction policy

    ✅ Always set maxmemory (128MB minimum) and maxmemory-policy allkeys-lru. Without limits, Redis can consume all RAM and crash your server.

    ❌ Forgetting to warm the cache after purging

    ✅ After a full cache purge, the first visitor to each page gets a slow uncached response. Use a cache warming script or crawler (e.g., WP Rocket's preload) to rebuild cache proactively.

    Caching Implementation Checklist

    ActionPriorityExpected Gain
    Enable full-page cachingCritical10–20x faster TTFB
    Enable OPcache with 256MB memoryCritical2–3x faster PHP
    Set browser cache headers for static assetsCritical50–80% fewer requests
    Add Cloudflare CDN (free tier)High30–70% faster globally
    Install Redis object cacheHigh30–50% fewer DB queries
    Configure cache invalidation rulesHighPrevents stale content
    Exclude dynamic pages from cacheHighPrevents data leaks
    Tune InnoDB buffer pool (70–80% RAM)HighFewer disk reads
    Enable cache preloading / warmingMediumNo cold-cache penalty
    Set up Gzip/Brotli compressionMedium60–80% smaller transfers
    Monitor cache hit ratesMediumVerify caching works
    Test site as logged-in vs logged-out userMediumCatch caching bugs
    Review cache settings after plugin updatesLowPrevent conflicts

    Frequently Asked Questions

    What is the most important type of caching for website speed?
    Full-page caching has the single biggest impact. It serves pre-generated HTML files instead of executing PHP and database queries on every request. With full-page caching enabled, a WordPress site can serve pages in 30–50ms instead of 300–800ms, a 10x improvement. Add a CDN on top for even faster delivery.
    What's the difference between Redis and Memcached?
    Both are in-memory key-value stores used for object caching. Redis supports more data types (lists, sets, sorted sets, hashes), persistence to disk, replication, and Lua scripting. Memcached is simpler, slightly faster for pure key-value lookups, and uses less memory per key. For WordPress and most web apps, Redis is the better choice due to its richer feature set and persistence.
    Does caching affect SEO?
    Yes, positively. Caching reduces TTFB and page load times, which directly improve Core Web Vitals (LCP, FID/INP). Google uses these as ranking signals. Sites with sub-200ms TTFB consistently rank higher than slow competitors. Additionally, faster sites reduce crawl budget waste, Googlebot can index more pages per crawl session.
    How do I know if my caching is working?
    Check HTTP response headers for cache indicators: 'X-Cache: HIT' (CDN cache hit), 'X-WP-Super-Cache: Served supercache file' (WordPress), or 'CF-Cache-Status: HIT' (Cloudflare). Use browser DevTools → Network tab to inspect headers. Also compare TTFB with and without cache, a properly cached page should respond in under 100ms.
    Should I cache dynamic content like shopping carts?
    No. Shopping carts, user dashboards, checkout pages, and any personalized content should bypass the cache. Most caching solutions automatically exclude logged-in users and specific URLs (e.g., /cart, /my-account). Caching dynamic content leads to users seeing other people's data, a serious privacy and security issue.
    Can too much caching cause problems?
    Yes. Over-caching can serve stale content, show outdated prices, or display old inventory counts. The key is proper cache invalidation, automatically purging cached content when the underlying data changes. Most caching plugins handle this for posts and pages, but custom post types and API responses may need manual invalidation rules.
    What's the difference between browser cache and CDN cache?
    Browser cache stores files on the user's local device; it's fastest but only helps returning visitors. CDN cache stores files on edge servers worldwide, it helps all visitors by serving content from the nearest geographic location. You should use both: CDN cache for first visits, browser cache for repeat visits.
    How much RAM does Redis need for WordPress?
    For a typical WordPress site with 500–1,000 posts, Redis needs 50–128MB of RAM. Large WooCommerce stores with 10K+ products may need 256–512MB. You can check actual usage with 'redis-cli INFO memory'. Most VPS plans with 2GB+ RAM have plenty of headroom for Redis alongside PHP and MySQL.

    Need Hosting With Built-In Caching?

    Skip the manual setup. Many managed hosts include page caching, CDN, Redis, and OPcache out of the box. Find the fastest option for your site.

    Compare Fast Hosting