Grav Caching Deep Dive — Cache Types, Warming and Cache Busting
In this tutorial, you'll learn Grav caching in depth — understanding cache types (file, Redis, Memcached), cache warming strategies, cache busting techniques, and optimizing cache configuration for maximum performance.
What You'll Learn
- Grav's caching architecture and cache types
- File-based caching vs Redis vs Memcached
- Cache warming: pre-rendering pages to cache
- Cache busting: forcing cache refresh when content changes
- Cache configuration for production
- Monitoring and debugging cache performance
Why It Matters
In WordPress, caching requires plugins like W3 Total Cache or server-level solutions. In Grav, caching is built into the core and configurable at multiple levels. Understanding cache types, expiration strategies, and warming techniques is the difference between a site that loads in 200ms and one that loads in 2 seconds. Proper caching is the single highest-impact performance optimization you can make.
Real-World Use
A documentation site with 5,000 pages was taking 4-6 seconds per page load. After enabling Redis caching with a 1-hour TTL and implementing cache warming (pre-caching all pages after every deployment), the average load time dropped to 80ms. The server CPU usage dropped from 80% to 15%. The improvement came entirely from proper cache configuration — no code changes.
Learning Path
flowchart LR
A["E-commerce with Grav"] --> B["Caching Deep Dive
← You are here"]:::current
B --> C["Performance Optimization"]
C --> D["Security"]
D --> E["Git Workflow"]
E --> F["CLI Tools"]
F --> G["Production Deployment"]
classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px
Cache Types
Grav supports three cache backends:
| Type | Storage | Speed | Best For |
|---|---|---|---|
| File | Disk | Medium | Development, low-traffic sites |
| Redis | Memory | Fast | High-traffic, multi-server setups |
| Memcached | Memory | Fast | Distributed caching, large sites |
File Cache (Default)
Configured in user/config/system.yaml:
cache:
enabled: true
driver: auto # auto = file-based by default
prefix: 'grav'
lifetime: 604800 # 7 days in seconds
gzip: true
clear_images_by_default: true
Redis Cache
cache:
enabled: true
driver: redis
prefix: 'grav'
lifetime: 604800
redis:
socket: false
server: 127.0.0.1
port: 6379
password: '' # Optional
database: 0
Install Redis:
sudo apt install redis-server php-redis
Memcached
cache:
enabled: true
driver: memcache
lifetime: 604800
memcache:
server: 127.0.0.1
port: 11211
Cache Layers
Grav caches at multiple levels:
Twig Cache
Compiled Twig templates are cached as PHP files:
twig:
cache: true
cache_path: 'cache://twig'
Page Cache
Full page output is cached:
cache:
enabled: true
check:
pages: true
yaml: true
twig: true
Asset Cache
Merged and minified CSS/JS are cached:
assets:
css_pipeline: true
css_minify: true
js_pipeline: true
js_minify: true
Cache Warming
Warm the cache by visiting all pages (pre-render and cache them):
user/plugins/cache-warmup/cli/WarmupCommand.php:
<?php
namespace Grav\Plugin\Console;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
class WarmupCommand extends ConsoleCommand
{
protected function configure()
{
$this
->setName('cache:warmup')
->setDescription('Warm up the cache by visiting all pages')
->addOption(
'concurrency',
'c',
InputOption::VALUE_OPTIONAL,
'Number of concurrent requests',
5
);
}
protected function serve($input, $output)
{
$this->setupConsole($input, $output);
$io = $this->getIO();
$concurrency = (int)$input->getOption('concurrency');
$pages = $this->grav['pages']->all();
$io->title('Cache Warming');
$io->writeln('Found ' . count($pages) . ' pages to warm');
$io->progressStart(count($pages));
$base = $this->grav['uri']->base();
foreach ($pages as $page) {
if ($page->published()) {
$url = $base . $page->route();
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_exec($ch);
curl_close($ch);
$io->progressAdvance();
}
}
$io->progressFinish();
$io->success('Cache warmed for ' . count($pages) . ' pages');
}
}
Run: bin/grav cache:warmup
Cache Busting
Force cache refresh when content changes:
cache:
check:
pages: true # Check if page modified time changed
yaml: true # Check if YAML config changed
twig: true # Check if Twig templates changed
Manual Cache Clear
# Clear all caches
bin/grav cache --clear
# Clear specific cache
bin/grav cache --clear-twig
bin/grav cache --clear-images
bin/grav cache --clear-assets
# Via PHP code
$this->grav['cache']->clearCache('all');
$this->grav['cache']->clearCache('twig');
$this->grav['cache']->clearCache('images');
Automatic Cache Busting
public function onAdminAfterSave()
{
// Clear cache when pages are saved
$this->grav['cache']->clearCache('standard');
}
Cache Configuration for Production
user/config/system.yaml:
cache:
enabled: true
driver: redis
prefix: 'grav'
lifetime: 604800
gzip: true
allow_url_fopen: false
check:
pages: true
yaml: false # Disable in production
twig: false # Disable in production
redis:
server: 127.0.0.1
port: 6379
twig:
cache: true
auto_reload: false
autoescape: true
assets:
css_pipeline: true
css_minify: true
js_pipeline: true
js_minify: true
enable_asset_timestamp: true
collections:
jquery: 'system://assets/jquery/jquery.min.js'
Monitoring Cache Performance
// Add to base template for debugging
{% if grav.user.authorize('admin.super') %}
<!-- Cache status -->
Cache hit: {{ grav.cache.getHitCount() }}
Cache miss: {{ grav.cache.getMissCount() }}
Cache size: {{ grav.cache.getSize() }}
{% endif %}
Learning Path
flowchart LR
A["E-commerce with Grav"] --> B["Caching Deep Dive
← You are here"]:::current
B --> C["Performance Optimization"]
C --> D["Security"]
D --> E["Git Workflow"]
E --> F["CLI Tools"]
classDef current fill:#38bdf8,color:#0f172a,stroke-width:2px
Common Mistakes
Not disabling
check.yamlandcheck.twigin production: Every check requires filesystem stats. In production, disable checks for YAML and Twig to eliminate unnecessary overhead.Using file cache for high-traffic sites: File cache works by reading/writing PHP files. For more than 10,000 requests/day, switch to Redis or Memcached for better performance.
Not warming cache after deployment: The first Visitor after deployment hits cold cache and gets a slow page. Always warm the cache after code or content changes.
Setting too short a cache lifetime: A 1-hour cache lifetime means every page is regenerated 24 times per day. Use 7 days (604800 seconds) and clear cache manually when content changes.
Forgetting to clear image cache after theme changes: Image manipulations are cached. If you change image styles or dimensions, clear the image cache to regenerate all images.
Practice Questions
What are the three cache drivers available in Grav? Answer: File (disk), Redis (memory), and Memcached (memory). File is the default and works for low-traffic sites. Redis and Memcached are recommended for production.
Why should you disable
check.yamlandcheck.twigin production? Answer: Each check requires Grav to stat files to see if they changed. Disabling these checks eliminates unnecessary filesystem operations, improving performance.How do you warm the cache for all pages? Answer: Use a CLI command (
bin/grav cache:warmup) that visits every published page via HTTP requests, forcing Grav to render and cache each one.What is the recommended cache lifetime for production? Answer: 604800 seconds (7 days). This long TTL means pages are rarely regenerated. Clear the cache manually when content changes.
Challenge: Set up a complete caching Strategy for a production Grav site. Install Redis and configure it as the cache driver. Configure production-optimized cache settings (disable YAML and Twig checks, 7-day lifetime). Create a cache warming CLI command. Set up automatic cache clearing on page saves. Verify cache hits by monitoring page load times before and after warming. Compare performance with file cache vs Redis. Document the setup for the operations team.
FAQ
Mini Project
Goal: Build and optimize a complete caching system for a Grav site.
- Install Redis and configure Grav to use it
- Configure production cache settings (7-day lifetime, disable checks)
- Create a cache warming plugin with a CLI command
- Add automatic cache clearing on page save events
- Create a cache monitoring dashboard widget
- Benchmark page load times: no cache, file cache, Redis cache
- Test cache invalidation when pages are modified
- Set up image caching and test regeneration on theme changes
- Configure asset pipeline caching with timestamps
- Document the caching architecture and procedures
What's Next
Now you understand caching. Next, learn performance optimization:
Continue to Lesson 36: Performance Optimization — Page speed, CDN, image optimization, and Performance Testing.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro