Performance
This guide covers strategies for building fast WPNuxt sites, from rendering mode selection to query optimization and Core Web Vitals.
SSR vs SSG
| SSR (Server-Side Rendering) | SSG (Static Site Generation) | |
|---|---|---|
| Build time | Fast (no pre-rendering) | Slower (fetches all content at build) |
| Time to first byte | ~50-200ms (with caching) | ~10-50ms (static files) |
| Content freshness | Real-time (with SWR) | Stale until rebuild |
| Best for | Frequently updated sites, many pages | Blogs, documentation, marketing sites |
| Hosting | Requires Node.js server | Any static host (CDN) |
For most WordPress sites, SSR with caching offers the best balance of freshness and performance. See the SSG guide if your content changes infrequently.
Lazy Loading Composables
Use lazy: true for content that isn't needed for the initial render:
<script setup lang="ts">
// Blocks navigation — use for primary content
const { data: post } = await useNodeByUri({ uri: route.path })
// Doesn't block navigation — use for secondary content
const { data: sidebar, pending } = usePosts(
{ limit: 5 },
{ lazy: true }
)
</script>
This lets the page render immediately with the primary content while secondary content loads in the background.
When to Use Each Mode
| Content | Option | Effect |
|---|---|---|
| Main page content | await (default) | Blocks navigation, included in SSR HTML |
| Sidebar, related posts | lazy: true | Page renders immediately, loads in background |
| Interactive widgets | server: false | Skips SSR, fetches client-side only |
| User-triggered content | immediate: false | No fetch until execute() is called |
See Fetching Data for full options documentation.
Image Optimization
Images are typically the largest assets on a page. Key optimizations:
- Set explicit dimensions to prevent Cumulative Layout Shift (CLS):
<NuxtImg :src="imageUrl" :width="featuredImage.mediaDetails?.width" :height="featuredImage.mediaDetails?.height" /> - Lazy load below-the-fold images:
<NuxtImg :src="imageUrl" loading="lazy" /> - Use modern formats with
<NuxtPicture>for automatic WebP/AVIF:<NuxtPicture :src="imageUrl" format="avif,webp" /> - Use an image provider (Cloudflare, Vercel, Imgix) for on-the-fly resizing and optimization.
See Images for the full image handling guide.
Route Rules for Per-Route Caching
Configure different caching strategies per route:
export default defineNuxtConfig({
routeRules: {
// Homepage: revalidate frequently
'/': { swr: 60 },
// Blog posts: cache longer, SWR for freshness
'/blog/**': { swr: 3600 },
// Static pages: cache aggressively
'/about': { swr: 86400 },
// API routes: short cache
'/api/**': { cache: { maxAge: 60 } },
},
})
Query Optimization
Use Fragments to Limit Fields
Default fragments include common fields. For listings where you only need titles and URIs, create a lighter fragment:
# extend/queries/fragments/PostListItem.gql
fragment PostListItem on Post {
id
title
uri
date
excerpt
featuredImage {
node {
sourceUrl
altText
}
}
}
Set Appropriate Limits
Always set a first value in list queries to avoid fetching more data than needed:
// Fetch only what you need
const { data: posts } = await usePosts({ limit: 10 })
// Don't fetch 100 posts if you show 5
const { data: recent } = await usePosts({ limit: 5 })
Avoid Redundant Fetches
Use clientCache: true (the default) to prevent re-fetching the same data during client-side navigation. See Caching for cache configuration details.
Lighthouse Tips
Largest Contentful Paint (LCP)
- Use SSR (default) so content is in the initial HTML
- Avoid
lazy: truefor above-the-fold content - Preload hero images with
<NuxtImg preload /> - Use an image CDN for optimized delivery
Cumulative Layout Shift (CLS)
- Always provide
widthandheightfor images - Use
placeholderon<NuxtImg>for loading states - Avoid content that loads and shifts the layout (use
lazy: trueonly for below-the-fold sections)
Total Blocking Time (TBT)
- Minimize client-side JavaScript with
server: true(default) - Use
lazy: trueto spread hydration work across time - Avoid large client-side data transformations — do them server-side in the GraphQL query or in a
transformoption
Quick Wins Checklist
- Enable server-side caching (
wpNuxt.cache.enabled: true— on by default) - Use
lazy: truefor sidebar and secondary content - Set explicit image dimensions to prevent CLS
- Use
loading="lazy"on below-the-fold images - Limit query results with
first/limitparameters - Use an image provider for production (Cloudflare, Vercel, etc.)
- Configure route rules for per-page caching strategies