Essentials

Performance Optimization

Optimize your Nuxt Contentstack application for speed, efficiency, and scalability with best practices, caching strategies, and performance tips.

Learn how to optimize your Nuxt Contentstack application for maximum performance. This guide covers caching strategies, request optimization, bundle size reduction, and performance monitoring.

Performance First: Performance optimization is crucial for user experience and SEO. Follow these best practices to ensure your application loads quickly and efficiently.

Overview

Performance optimization involves multiple aspects:

  • Request Optimization: Reduce API calls and optimize queries
  • Caching Strategies: Implement effective caching for static and dynamic content
  • Image Optimization: Optimize images for fast loading
  • Bundle Size: Reduce JavaScript bundle size
  • Code Splitting: Implement proper code splitting strategies
  • Monitoring: Track and measure performance metrics

Request Optimization

Reduce API Calls

Minimize the number of API requests by:

Instead of multiple separate queries, fetch related content together:

<!-- ❌ Bad - Multiple requests -->
<script setup>
const { data: page } = await useGetEntryByUrl({
  contentTypeUid: 'page',
  url: '/about'
})
const { data: posts } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit: 5
})
</script>

<!-- ✅ Good - Single request with references -->
<script setup>
const { data: page } = await useGetEntryByUrl({
  contentTypeUid: 'page',
  url: '/about',
  referenceFieldPath: ['featured_posts'] // Include related content
})
</script>

2. Use Reference Fields

Include referenced content in a single request:

<script setup>
// ✅ Fetches entry + author + category in one request
const { data: post } = await useGetEntry({
  contentTypeUid: 'blog_post',
  entryUid: 'blt123',
  referenceFieldPath: ['author', 'category', 'related_posts']
})
</script>

3. Limit Fields

Only fetch fields you need (if Contentstack API supports field selection):

<script setup>
// Fetch only necessary fields
const { data: posts } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit: 10,
  // Use specific field paths if supported
})
</script>

Optimize Query Parameters

Use Appropriate Limits

<script setup>
// ✅ Good - Reasonable limit
const { data: posts } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit: 10 // Only fetch what you need
})

// ❌ Bad - Fetching too much
const { data: posts } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit: 1000 // Unnecessary data
})
</script>

Implement Pagination

<script setup>
const route = useRoute()
const page = computed(() => parseInt(route.query.page) || 1)
const limit = 10
const skip = computed(() => (page.value - 1) * limit)

const { data: result } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit,
  skip: skip.value,
  includeCount: true
})
</script>

Lazy Loading

Load content only when needed:

<script setup>
// Lazy load content
const { data: posts, pending } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit: 10
}, {
  lazy: true, // Don't block page load
  server: false // Client-side only
})
</script>

Caching Strategies

Static Content Caching

Cache content that rarely changes:

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/about': {
      swr: 3600, // Cache for 1 hour
      headers: {
        'Cache-Control': 's-maxage=3600'
      }
    },
    '/blog/**': {
      swr: 1800, // Cache for 30 minutes
    }
  }
})

Dynamic Content Caching

Implement smart caching for frequently updated content:

<script setup>
const { data: posts, refresh } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit: 10
})

// Refresh cache periodically
const refreshInterval = setInterval(() => {
  refresh()
}, 5 * 60 * 1000) // Every 5 minutes

onUnmounted(() => clearInterval(refreshInterval))
</script>

Cache Invalidation

Invalidate cache when content changes:

composables/useContentRefresh.ts
export const useContentRefresh = () => {
  const refreshAll = async () => {
    // Refresh all content composables
    await refreshCookie('contentstack')
  }
  
  return { refreshAll }
}

Image Optimization

Use @nuxt/image

Leverage Contentstack's image provider for automatic optimization:

<template>
  <!-- ✅ Optimized with automatic format conversion -->
  <NuxtImg
    :src="image.url"
    :alt="image.title"
    width="800"
    height="400"
    :modifiers="{ auto: 'webp,compress', quality: 85 }"
    provider="contentstack"
    loading="lazy"
  />
</template>

Responsive Images

Use responsive images for different screen sizes:

<template>
  <NuxtPicture
    :src="hero.image.url"
    :imgAttrs="{ alt: hero.image.title }"
    sizes="100vw sm:90vw md:80vw lg:1200px"
    :modifiers="{ quality: 85, auto: 'webp,compress' }"
    provider="contentstack"
  />
</template>

Image Preloading

Preload critical images:

<script setup>
const { data: page } = await useGetEntryByUrl({
  contentTypeUid: 'page',
  url: '/'
})

if (page.value?.hero?.image) {
  useHead({
    link: [
      {
        rel: 'preload',
        href: page.value.hero.image.url,
        as: 'image'
      }
    ]
  })
}
</script>

Bundle Size Optimization

Code Splitting

Implement proper code splitting:

<script setup>
// ✅ Lazy load heavy components
const HeavyComponent = defineAsyncComponent(() => 
  import('~/components/HeavyComponent.vue')
)
</script>

<template>
  <HeavyComponent v-if="showHeavy" />
</template>

Tree Shaking

Import only what you need:

// ✅ Good - Import specific functions
import { useGetEntry } from '#imports'

// ❌ Bad - Import entire module
import * as Contentstack from '#imports'

Reduce Dependencies

Minimize external dependencies:

package.json
{
  "dependencies": {
    "nuxt-contentstack": "^latest",
    "@nuxt/image": "^2.0.0"
    // Only essential dependencies
  }
}

Performance Monitoring

Measure Performance

Use browser DevTools and performance APIs:

composables/usePerformance.ts
export const usePerformance = () => {
  const measureContentLoad = (name: string) => {
    if (import.meta.client && 'performance' in window) {
      const mark = `content-${name}-start`
      performance.mark(mark)
      
      return () => {
        const endMark = `content-${name}-end`
        performance.mark(endMark)
        performance.measure(`content-${name}`, mark, endMark)
        
        const measure = performance.getEntriesByName(`content-${name}`)[0]
        console.log(`${name} loaded in ${measure.duration}ms`)
      }
    }
    return () => {}
  }
  
  return { measureContentLoad }
}

Track API Performance

Monitor API request times:

<script setup>
const startTime = Date.now()

const { data: posts } = await useGetEntries({
  contentTypeUid: 'blog_post',
  limit: 10
})

const loadTime = Date.now() - startTime
console.log(`Posts loaded in ${loadTime}ms`)
</script>

Best Practices Summary

Do's ✅

  • Use reference fields to fetch related content in one request
  • Implement proper pagination for large datasets
  • Cache static content aggressively
  • Optimize images with @nuxt/image
  • Use lazy loading for non-critical content
  • Monitor performance metrics
  • Implement code splitting for large components

Don'ts ❌

  • Don't fetch more data than needed
  • Don't make unnecessary API calls
  • Don't ignore cache invalidation
  • Don't load all images immediately
  • Don't bundle unnecessary dependencies
  • Don't block page load with heavy queries
  • Don't ignore performance monitoring

Performance Checklist

Use this checklist to optimize your application:

  • Reduced API calls using reference fields
  • Implemented pagination for large datasets
  • Configured appropriate cache strategies
  • Optimized images with @nuxt/image
  • Implemented lazy loading for non-critical content
  • Reduced bundle size with code splitting
  • Set up performance monitoring
  • Tested on slow networks
  • Verified Core Web Vitals

Next Steps

Caching Guide

Learn more about caching strategies in the composables guide.

Image Optimization

Deep dive into image optimization techniques.