Caching
Every composable call triggers a network request to your WordPress GraphQL API. Without caching, each page load costs ~200-500ms waiting for WordPress to respond. With caching enabled (the default), repeated requests resolve in ~1-5ms — making your site feel instant.
WPNuxt provides multiple layers of caching to achieve this. See How WPNuxt Works for where caching fits in the overall architecture.
Cache Layers
| Layer | Scope | Duration | Purpose |
|---|---|---|---|
| Server (Nitro) | All users | Configurable | Cache GraphQL responses server-side |
| Client (GraphQL) | Per browser | Session | Deduplicate identical queries during navigation |
| Payload | Per request | Hydration | Prevent refetch after SSR |
All layers work together automatically.
Server-Side Caching
WPNuxt caches GraphQL responses server-side using Nitro route rules.
How It Works
- First request fetches from WordPress (~200-500ms)
- Response is cached on the server
- Subsequent requests use cache (~1-5ms)
- With SWR enabled, stale content serves instantly while refreshing in background
Configuration
wpNuxt: {
cache: {
enabled: true, // Default: true
maxAge: 300, // Default: 300 (5 minutes)
swr: true // Default: true
}
}
| Option | Default | Description |
|---|---|---|
enabled | true | Enable/disable caching |
maxAge | 300 | Cache duration in seconds |
swr | true | Stale-while-revalidate |
Client-Side Caching
WPNuxt enables client-side GraphQL caching by default. This deduplicates identical queries during client-side navigation.
Per-Query Control
// Disable client caching for real-time data
const { data } = usePosts(undefined, { clientCache: false })
// Custom cache key for complex scenarios
const { data } = usePosts({ category: 'news' }, {
cacheKey: `posts-news-${locale.value}`
})
| Option | Type | Default | Description |
|---|---|---|---|
clientCache | boolean | true | Enable client-side caching |
cacheKey | string | - | Custom cache key suffix |
Payload Caching (getCachedData)
WPNuxt optimizes SSR payload handling with a smart getCachedData implementation:
- During hydration: Uses payload data (no refetch needed)
- Watch-triggered refetches: Uses cached data when available
- Manual refresh: Always fetches fresh data
Custom getCachedData
Override the default behavior for specific use cases:
const { data } = usePosts(undefined, {
getCachedData: (key, nuxtApp, ctx) => {
// Always fetch fresh
if (ctx.cause === 'refresh:manual') {
return undefined
}
// Use cached data
return nuxtApp.payload.data[key]
}
})
The ctx.cause can be:
'initial'- First load'refresh:manual'- Calledrefresh()'refresh:hook'- Triggered by Nuxt hook'watch'- Reactive dependency changed
When to Disable Caching
Development
// See changes immediately
wpNuxt: {
cache: {
enabled: false
}
}
Real-Time Content
// Per-query: disable for live data
const { data } = useLiveComments(undefined, { clientCache: false })
// Global: short cache with no SWR
wpNuxt: {
cache: {
maxAge: 60,
swr: false
}
}
Authenticated Content
Authenticated requests bypass server cache automatically (via Authorization header). For user-specific data, disable client caching. See also Preview Mode for how caching interacts with draft content previews.
const { data } = useViewer(undefined, { clientCache: false })
High-Traffic Sites
wpNuxt: {
cache: {
maxAge: 3600, // 1 hour
swr: true
}
}
Recommended Strategies
| Site Type | maxAge | swr | clientCache | Why |
|---|---|---|---|---|
| Blog / content site | 300–3600 | true | true | Content changes infrequently, SWR keeps it fresh |
| News / frequently updated | 60 | true | true | Short cache + SWR = fresh content without latency |
| Dashboard / real-time | 0 | false | false | Always fetch latest data |
| E-commerce catalog | 300 | true | true | Product data is mostly stable |
Cache Invalidation
Manual Refresh
const { data, refresh } = usePosts()
// Force fresh data
await refresh()
Reactive Invalidation
const category = ref('news')
const { data } = usePosts(
{ categoryName: category },
{ watch: [category] }
)
// Changing category triggers refetch
category.value = 'tech'
Server Cache
Server cache automatically expires based on maxAge. For immediate invalidation, you'll need to implement a webhook from WordPress or use a CDN with cache purge capabilities.
Related Pages
- Performance — Broader performance optimization strategies
- Preview Mode — How caching is bypassed for draft content
- Configuration — All cache configuration options