---
title: "Nuxt Performance Guide: Core Web Vitals und Lighthouse optimieren"
description: "Wie du mit Nuxt 3 und 4 perfekte Lighthouse Scores erreichst. Strategien für Core Web Vitals, Nuxt Image, Lazy Hydration und mehr. Jetzt optimieren!"
canonical_url: "https://www.blueshoe.de/blog/nuxt-lighthouse-performance/"
---

Performance ist mittlerweile ein echter Ranking-Faktor - nicht mehr nur ein "nice to have". Nuxt (3 und 4) bringt zwar schon eine solide Basis mit, aber für einen perfekten Lighthouse Score von 100/100 braucht es mehr als die Standard-Konfiguration. In diesem Artikel lernst du Strategien, die wirklich funktionieren und mit denen du jede Nuxt-App optimieren kannst.

![Nuxt Performance Optimierung](/img/blogs/vuejsnuxt.svg)

<global-blog-level-info>

- Grundlagen zu [Nuxt 3/4](https://nuxt.com/docs)
- [Vue.js](https://vuejs.org/) Basics
- [Core Web Vitals](https://web.dev/articles/vitals) und [Lighthouse](https://developer.chrome.com/docs/lighthouse/)
- Kontext zu Rendering-Modi: [Nuxt Generate vs. Server](/blog/nuxt-generate-vs-server/)

Solltest du Fragen haben, oder dir etwas unklar sein, kannst du die Kommentarfunktion unter dem Artikel nutzen.

</global-blog-level-info>

Wir schauen uns an, wie Hybrid Rendering funktioniert, wie Nuxt Image und Nuxt Scripts die Performance verbessern, und wie Lazy Hydration dabei hilft, die [Total Blocking Time (TBT)](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-total-blocking-time?hl=de) zu reduzieren. Die Tipps funktionieren sowohl für E-Commerce-Plattformen als auch für content-lastige Marketing-Websites.

## Warum Lighthouse für Nuxt-Apps wichtig ist

Wenn du schon mal eine Nuxt-App gebaut hast, kennst du das Problem: Die App fühlt sich schnell an, aber Lighthouse zeigt trotzdem nicht die gewünschten Scores. Das liegt daran, dass SPAs und hydratisierte Apps oft mit initialen Lade-Metriken kämpfen – selbst wenn Nuxt 3 und 4 SSR und SSG unterstützen.

Google nutzt Core Web Vitals mittlerweile als Ranking-Signal. Das bedeutet: Schlechte Performance-Metriken können deine Sichtbarkeit in den Suchergebnissen direkt beeinflussen. Und das wirkt sich nicht nur auf SEO aus, sondern auch auf Conversion-Rates.

Der Trick ist, nicht nur darauf zu achten, dass sich die App schnell anfühlt, sondern dass sie auch schnell gemessen wird. Mit den richtigen Strategien ist ein perfekter Lighthouse Score von 100/100 auch mit Nuxt erreichbar.

## Der richtige Rendering-Modus macht den Unterschied

Bevor wir in die Details gehen, lass uns kurz klären, welche Rendering-Modi es gibt und wann welcher Sinn macht. Mit SSR (`ssr: true`) werden Seiten bei jeder Anfrage auf dem Server gerendert – gut für dynamische Inhalte, aber das Time to First Byte (TTFB) leidet. SSG (`ssr: false` mit `nitro.prerender`) generiert Seiten beim Build – extrem schnell, aber keine dynamischen Inhalte. Und CSR (`ssr: false`) läuft komplett im Browser – schnell, aber schlecht für SEO.

Der echte Game Changer ist aber Hybrid Rendering. Nuxt 3 und 4 erlauben dir, verschiedene Rendering-Strategien für verschiedene Routen zu nutzen. Das ist der Schlüssel zu optimaler Performance:

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // Statische Marketing-Seiten: Sofort verfügbar
    "/": { prerender: true },
    "/ueber-uns": { prerender: true },
    "/kontakt": { prerender: true },
    
    // Dynamische Inhalte: SWR für frische Daten mit schnellem TTFB
    "/blog/**": { swr: 3600 }, // 1 Stunde Cache
    "/produkte/**": { swr: 1800 }, // 30 Minuten Cache
    
    // Echtzeit-Daten: Immer frisch
    "/dashboard/**": { ssr: true },
    
    // Client-only: Für interaktive Komponenten
    "/admin/**": { ssr: false }
  }
})
```

Die Strategie ist einfach: Verwende SWR (Stale-While-Revalidate) für dynamische Inhalte wie Blog-Posts oder Produktseiten. Das sorgt für frische Daten bei gleichzeitig schnellem TTFB. Für statische Marketing-Seiten wie "Über uns" oder "Kontakt" nutzt du Prerendering – die sind dann sofort verfügbar.

## LCP optimieren: Das größte sichtbare Element zählt

[LCP (Largest Contentful Paint)](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint?hl=de) misst, wann das größte sichtbare Element im Viewport geladen wird. Meistens ist das ein großes Hero-Bild oder ein render-blockierendes Element. Wenn das zu lange dauert, leidet dein Lighthouse Score.

### Nuxt Image macht den Unterschied

Das [@nuxt/image](https://image.nuxt.com/) Modul sollte in keiner optimierten Nuxt-App fehlen. Es macht Bild-Optimierung fast automatisch:

```bash
npm install @nuxt/image
```

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@nuxt/image"],
  image: {
    format: ["webp", "avif"],
    quality: 80,
    screens: {
      xs: 320,
      sm: 640,
      md: 768,
      lg: 1024,
      xl: 1280,
      xxl: 1536,
    },
  }
})
```

**So verwendest du es in Komponenten**:

```vue
<template>
  <NuxtImg
    src="/hero-image.jpg"
    alt="Hero Image"
    :sizes='{ sm: "100vw", md: "50vw", lg: "33vw" }'
    loading="eager"
    fetchpriority="high"
    preload
  />
</template>
```

Wichtig: Für dein LCP-Element solltest du `preload` und `fetchpriority="high"` verwenden. Das `sizes` Prop sorgt dafür, dass Mobile-User nicht die Desktop-Version laden müssen. Und die automatische Format-Konvertierung zu WebP oder AVIF spart richtig viel Datenvolumen.

### Fonts richtig laden

Web-Fonts können dein LCP richtig in die Knie zwingen, wenn sie nicht optimiert sind. Hier hilft `@nuxt/fonts`:

```bash
npm install @nuxt/fonts
```

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@nuxt/fonts"],
  fonts: {
    families: [
      { name: "Inter", provider: "google" }
    ]
  }
})
```

**Implementierung**:

```vue
<style>
@font-face {
  font-family: "Inter";
  font-display: swap; /* Verhindert unsichtbaren Text während des Ladens */
}
</style>
```

Mit `font-display: swap` wird der Text sofort mit einer Fallback-Schriftart angezeigt, während die Web-Font im Hintergrund lädt. So gibt es keine unsichtbaren Textblöcke mehr.

## CLS eliminieren: Keine Layout-Sprünge mehr

[Cumulative Layout Shift (CLS)](https://web.dev/articles/cls?hl=de) ist der Albtraum jedes Frontend-Entwicklers. Nichts ist nerviger als Seiten, die beim Laden hin und her springen. Die häufigsten Übeltäter sind Bilder ohne Dimensionen, spät ladende Werbeanzeigen, Web-Fonts ohne `font-display: swap` und dynamisch injizierter Content.

Mit Nuxt kannst du das aber gut in den Griff bekommen:

**Aspect Ratios für alle Medien erzwingen**:

```vue
<template>
  <NuxtImg
    src="/product.jpg"
    alt="Product"
    :width="800"
    :height="600"
    loading="lazy"
  />
</template>
```

**Platzhalter für dynamische Inhalte**:

```vue
<template>
  <div class="product-card">
    <!-- Platzhalter während des Ladens -->
    <div v-if="loading" class="skeleton">
      <div class="skeleton-image"></div>
      <div class="skeleton-text"></div>
    </div>
    
    <!-- Echter Content -->
    <ClientOnly>
      <ProductDetails :product="product" />
      <template #fallback>
        <div class="skeleton">Lädt...</div>
      </template>
    </ClientOnly>
  </div>
</template>
```

**Reservierter Platz für dynamische Komponenten**:

```vue
<template>
  <!-- Fester Container verhindert Layout-Shift -->
  <div class="ad-container" style="min-height: 250px;">
    <ClientOnly>
      <AdBanner />
    </ClientOnly>
  </div>
</template>
```

## TBT und INP reduzieren: JavaScript nicht blockieren lassen

Wenn zu viel JavaScript auf dem Haupt-Thread läuft, blockiert das die Interaktivität. [TBT (Total Blocking Time)](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-total-blocking-time?hl=de) misst, wie lange der Haupt-Thread blockiert ist, [INP (Interaction to Next Paint)](https://web.dev/articles/inp?hl=de) misst die Reaktionszeit auf Klicks und andere Interaktionen.

### Third-Party-Skripte clever laden

Mit [@nuxt/scripts](https://scripts.nuxt.com/) lädst du Third-Party-Skripte wie Google Tag Manager oder Google Analytics mit guten Ladezeiten und ohne das Rendering zu blockieren. Die offizielle Doku unterscheidet zwischen **Registry Scripts** (vorgefertigte Integrationen) und **Global Scripts** (beliebige Skript-URLs).

**Installation:**

```bash
npm install @nuxt/scripts
```

**Registry Scripts** – für unterstützte Dienste wie GTM oder Google Analytics reicht die Angabe der ID. Standardmäßig werden die Skripte geladen, wenn Nuxt fertig hydratisiert ist (`onNuxtReady`), also nicht während des ersten Paints:

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@nuxt/scripts"],
  scripts: {
    registry: {
      googleTagManager: { id: "GTM-XXXXXXX" },
      googleAnalytics: { id: "G-XXXXXXXXXX" },
    },
  },
})
```

**Global Scripts** – für beliebige Skript-URLs (z.B. eigenes Analytics oder Tracking) nutzt du `globals`. Per Array kannst du [Script Options](https://scripts.nuxt.com/docs/api/use-script#nuxtusescriptoptions) wie `trigger` mitgeben:

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@nuxt/scripts"],
  scripts: {
    globals: {
      // Nur URL – wird mit Default-Optionen geladen (z. B. onNuxtReady)
      myTracker: "https://analytics.example.com/tracker.js",
      // Mit Optionen: z. B. erst nach Hydration laden
      myScript: [
        { src: "https://example.com/script.js" },
        { trigger: "client" },
      ],
    },
  },
})
```

Zugriff auf global registrierte Skripte hast du über `useNuxtApp().$scripts` (z.B. `$scripts.myTracker`). So bleiben Third-Party-Skripte kontrolliert geladen und blockieren den Haupt-Thread nicht während des initialen Renderings.

### Komponenten nur laden, wenn sie gebraucht werden

Nuxt macht Lazy Loading super einfach. Mit dem `Lazy` Prefix werden Komponenten erst geladen, wenn sie wirklich benötigt werden:

```vue
<template>
  <!-- Wird nur geladen, wenn benötigt -->
  <LazyModal v-if="showModal" />
  <LazyChart v-if="showChart" />
</template>
```

Für schwere Bibliotheken wie Chart.js kannst du dynamische Imports nutzen:

```vue
<script setup>
const loadChart = async () => {
  // Wird erst importiert, wenn der User zum Chart scrollt
  const { Chart } = await import("chart.js")
  // Chart initialisieren...
}
</script>

<template>
  <div @intersect="loadChart">
    <ChartComponent />
  </div>
</template>
```

### Lazy Hydration: Der fortgeschrittene Trick

Lazy Hydration ist ein echter Game Changer. Statt alle Komponenten sofort zu hydratisieren, passiert das erst, wenn sie wirklich gebraucht werden:

```bash
npm install nuxt-delay-hydration
```

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["nuxt-delay-hydration"],
  delayHydration: {
    mode: "mount",
    idleTimeout: 5000, // Hydration nach 5 Sekunden Idle-Zeit
    replayClick: true
  }
})
```

**Manuell kannst du Lazy Hydration so umsetzen**:

```vue
<script setup>
import { useIntersectionObserver } from "@vueuse/core"

const target = ref(null)
const shouldHydrate = ref(false)

useIntersectionObserver(
  target,
  ([{ isIntersecting }]) => {
    if (isIntersecting) {
      shouldHydrate.value = true
    }
  }
)
</script>

<template>
  <div ref="target">
    <ClientOnly v-if="shouldHydrate">
      <HeavyComponent />
    </ClientOnly>
    <div v-else class="placeholder">Scroll für mehr...</div>
  </div>
</template>
```

Das Ergebnis: Die Hydration passiert erst, wenn die Komponente in den Viewport scrollt. Das reduziert TBT erheblich und macht deine App deutlich schneller.

## SEO: Die technische Grundlage

Für SEO eignet sich [@nuxtjs/seo](https://nuxtseo.com/) sehr gut. Das Modul ist eine echte "set and forget" Lösung – einmal konfiguriert, kümmert es sich um die meisten SEO-Best-Practices:

```bash
npm install @nuxtjs/seo
```

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@nuxtjs/seo"],
  site: {
    url: "https://www.deine-domain.de",
    name: "Dein Projekt",
    description: "Deine Performance-optimierte Website",
  },
  sitemaps: {
    hostname: "https://www.deine-domain.de",
  }
})
```

Das Modul generiert automatisch Sitemaps und robots.txt, macht Schema.org-Structured Data super einfach und verwaltet Meta-Tags für Social Sharing. Mit `useSeoMeta` und `useSchemaOrg` hast du alles, was du brauchst.

**So verwendest du es in Komponenten**:

```vue
<script setup>
useSeoMeta({
  title: "Produktseite",
  description: "Beschreibung des Produkts",
  ogImage: "/product-image.jpg",
  twitterCard: "summary_large_image"
})

useSchemaOrg([
  {
    "@type": "Product",
    name: "Produktname",
    description: "Produktbeschreibung",
    image: "/product-image.jpg",
    offers: {
      "@type": "Offer",
      price: "99.99",
      priceCurrency: "EUR"
    }
  }
])
</script>
```

## Performance kontinuierlich überwachen

### Unlighthouse: Alle Seiten testen, nicht nur die Homepage

[Unlighthouse](https://unlighthouse.dev/) ist ein empfehlenswertes Tool für Performance-Tests. Es scannt jede Seite deiner Website, nicht nur die Homepage:

```bash
npm install -D unlighthouse
```

```typescript
// unlighthouse.config.ts
export default {
  site: "https://www.deine-domain.de",
  urls: [
    "/",
    "/blog",
    "/produkte",
    // ... alle wichtigen Seiten
  ],
  lighthouseOptions: {
    onlyCategories: ["performance", "seo", "accessibility"]
  }
}
```

**So führst du es aus**:

```bash
npx unlighthouse --site https://www.deine-domain.de
```

### CI/CD Integration

Lighthouse-Checks in deinen Pull-Request-Workflow integrieren:

```yaml
# .github/workflows/lighthouse.yml
name: Lighthouse CI

on:
  pull_request:
    branches: [main]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npm run build
      - run: npm run preview &
      - uses: treosh/lighthouse-ci-action@v9
        with:
          urls: |
            http://localhost:3000
            http://localhost:3000/blog
          uploadArtifacts: true
          temporaryPublicStorage: true
```

Das Schöne daran: Du erkennst Performance-Regressionen automatisch, überwachst die Core Web Vitals kontinuierlich und findest Probleme, bevor sie in Production landen.

## Quick-Check: Hast du alles?

Bevor du loslegst, hier ein kurzer Check der wichtigsten Punkte: Nuxt Image installiert? LCP-Bild mit `preload` und `fetchpriority="high"` markiert? Fonts optimiert? Aspect Ratios definiert? Hybrid Rendering konfiguriert? Third-Party-Skripte mit Nuxt Scripts geladen? Lazy Loading und Lazy Hydration aktiv? SEO-Modul installiert? Unlighthouse für Monitoring eingerichtet?

Wenn du alle Punkte abhaken kannst, bist du auf einem sehr guten Weg zu perfekten Lighthouse Scores.

## Fazit

Performance-Optimierung ist kein einmaliger Fix, sondern ein kontinuierlicher Prozess. Mit Nuxt 3 und 4 hast du alle Tools, die du brauchst, um perfekte Lighthouse Scores zu erreichen. Die Kombination aus Hybrid Rendering, optimierten Assets und intelligenter Hydration-Strategie führt zu messbar besseren Core Web Vitals.

Mein Tipp: Starte mit einem Lighthouse-Audit deiner aktuellen App, identifiziere die größten Bottlenecks und implementiere dann eine Optimierung nach der anderen. Selbst kleine Verbesserungen können große Auswirkungen haben.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
