Eu24 Web

Performance

Introduction

Performance is critical for modern web applications—not only for delivering a smooth user experience but also for improving SEO rankings and reducing infrastructure costs. Nuxt 3, with its modern architecture built on top of Vue 3 and Vite/Nitro, provides a solid foundation for building high-performance web apps. However, to truly unlock its potential, developers need to follow best practices and implement strategic optimizations throughout the codebase.

This guide compiles essential tips and practical code examples to help you optimize your Nuxt 3 application for performance. From leveraging dynamic imports and managing state efficiently to optimizing asset delivery and enabling server-side caching, every section is crafted to reduce bundle size, improve load times, and enhance overall responsiveness.


1. Keep Pinia Stores Lean

Move business logic out of stores and into services or utils.

Example:

export const useCartStore = defineStore("cartStore", {
  state: () => ({
    cartItems: [],
  }),
  actions: {
    async addToCart(context, item) {
      const { addToCart } = await import("~/services/cartService");
      return await addToCart(context, item);
    },
  },
});

2. Disable Component Auto Import

Update nuxt.config.ts:

components: {
  global: true,
  dirs: ['~/components/global'],
}

Import components dynamically:

const Example = defineAsyncComponent(() => import("@/components/Example.vue"));

3. Add Compression and Caching for Assets

Update nuxt.config.ts:

nitro: {
  compressPublicAssets: true,
  minify: true,
  serveStatic: {
    headers: {
      'Cache-Control': 'public, max-age=31536000, immutable',
    },
  },
}

4. Add async and defer to Scripts

Use these attributes in custom scripts to avoid blocking page rendering.


5. Monitor Build Sizes

Run:

npm run build

Keep an eye on build output sizes.


6. Use transform to Optimize Payload

Video Reference


7. Use <ClientOnly> for Non-SEO Critical Components

<ClientOnly>
  <NewsLetter />
</ClientOnly>

8. Use Pinia Effectively

Pinia Best Practices


9. Dynamic Loading of Services

Avoid using stores inside services. Instead, pass store instances from components or pages.

In Page/Component:

<script setup>
import { onMounted } from 'vue';
const myStore = useMyStore();

onMounted(async () => {
  const { getItem } = await import('~/services/myService');
  myStore.item = await getItem(myStore);
});
</script>

In Middleware:

export default defineNuxtRouteMiddleware(async (to, from) => {
  if (to.path.startsWith("/protected")) {
    const { useAuthStore } = await import("~/stores/auth");
    const authStore = useAuthStore();

    if (!authStore.isAuthenticated) {
      return navigateTo("/login");
    }
  }
});

10. Use Exported Functions for Smaller Bundles

Preferred:

// utils.ts
export const foo = () => {
  /* ... */
};
export const bar = () => {
  /* ... */
};

// usage
import { foo, bar } from "./utils";

Avoid:

// MyClass.ts
export class MyClass {
  foo() {
    /* ... */
  }
  bar() {
    /* ... */
  }
}

// usage
import { MyClass } from "./MyClass";
const myInstance = new MyClass();
myInstance.foo();

11. SSR API Calls with useAsyncData

const { data } = await useAsyncData("results", async () => {
  const { searchResult } = await import("@/services/algoliaService");
  return searchResult();
});

12. Cache API Routes

Use cachedEventHandler:


13. Custom getCachedData in useAsyncData

const { data, error, pending } = await useAsyncData(
  "getPopularKeywords",
  async () => {
    const { getPopularKeywords } = await import(
      "@/services-optimized/builderService"
    );
    return await getPopularKeywords(runtimeConfig.public.builderApiKey);
  },
  {
    immediate: true,
    getCachedData(key) {
      if (!debug) {
        const cachedData =
          nuxtApp.payload.data[key] || nuxtApp.static.data[key];
        if (!cachedData) return;

        const expirationTime = new Date(cachedData.fetchedAt);
        expirationTime.setTime(expirationTime.getTime() + 1000 * 60 * 60);

        const isExpired = expirationTime.getTime() < new Date().getTime();
        if (isExpired) return;
      }
    },
  }
);

Copyright © 2026