Ein Lighthouse-Score von 90+ ist kein Zufall - es ist das Ergebnis konsequenter Optimierung. In diesem Guide zeigen wir Ihnen 15 bewährte Techniken, mit denen wir bei HEADON.pro durchschnittlich 60% Performance-Steigerung erreichen.
Warum Performance kritisch ist
Jede Sekunde Ladezeit kostet Sie Nutzer und Umsatz:
- 53% der Mobile-Nutzer verlassen Seiten, die >3 Sekunden laden
- 100ms schnellere Ladezeit = 1% mehr Conversions (Amazon-Studie)
- Google-Ranking berücksichtigt Core Web Vitals seit 2021
Unsere Messungen aus Portfolio-Projekten zeigen: Optimierte Next.js-Apps erreichen LCP < 1.0s und FCP < 0.5s.
1. Dynamic Imports für Code-Splitting
Laden Sie nur Code, der wirklich benötigt wird:
// ❌ Schlecht: Alles im Initial Bundle
import { HeavyChart } from '@/components/charts'
import { ComplexModal } from '@/components/modal'
import { RarelyUsedWidget } from '@/components/widgets'
export default function Dashboard() {
return (
<div>
<HeavyChart data={data} />
<ComplexModal />
<RarelyUsedWidget />
</div>
)
}
// ✅ Gut: Lazy Loading mit dynamic()
import dynamic from 'next/dynamic'
const HeavyChart = dynamic(() => import('@/components/charts/HeavyChart'), {
loading: () => <ChartSkeleton />,
ssr: false, // Nicht Server-Side rendern wenn nicht nötig
})
const ComplexModal = dynamic(() => import('@/components/modal/ComplexModal'))
export default function Dashboard() {
return (
<div>
<HeavyChart data={data} />
<ComplexModal />
</div>
)
}
Einsparung: Bis zu 40% kleinerer Initial Bundle.
Named Exports mit dynamic()
// ✅ Für Named Exports
const SpecificComponent = dynamic(
() => import('@/components/library').then(mod => mod.SpecificComponent)
)
2. Image Optimization perfektionieren
Die next/image
Komponente ist mächtig - wenn richtig konfiguriert:
import Image from 'next/image'
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Hero Image"
width={1920}
height={1080}
// ✅ Priority für Above-the-Fold Images
priority
// ✅ Sizes für Responsive Images
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
// ✅ Optimale Quality (85 ist sweet spot)
quality={85}
// ✅ Placeholder mit Blur Effect
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
/>
)
}
Bildformat-Strategie
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
minimumCacheTTL: 60,
},
}
Ergebnis:
- AVIF: 30% kleiner als WebP
- WebP: 25-35% kleiner als JPEG
- Automatisches Format-Switching basierend auf Browser-Support
Mehr Details in unserem Image Optimization Guide.
3. Font-Loading optimieren
Google Fonts effizient laden mit next/font
:
// app/layout.tsx
import { Inter, Playfair_Display } from 'next/font/google'
// ✅ Subset definieren spart Bytes
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
display: 'swap',
preload: true,
})
const playfair = Playfair_Display({
subsets: ['latin'],
variable: '--font-playfair',
weight: ['400', '700'], // Nur benötigte Weights
display: 'swap',
})
export default function RootLayout({ children }) {
return (
<html lang="de" className={`${inter.variable} ${playfair.variable}`}>
<body>{children}</body>
</html>
)
}
Vorteile:
- ⚡ Fonts werden automatisch optimiert
- 🚀 Self-hosted (kein externes Google-Request)
- 🎯 Zero Layout Shift durch font-display: swap
- 📦 CSS-Variablen für flexible Nutzung
4. Aggressive Caching-Strategie
Fetch-Caching konfigurieren
// ✅ Static Data - Cache unbegrenzt
const staticData = await fetch('https://api.example.com/config', {
cache: 'force-cache', // Default in App Router
})
// ✅ Revalidate nach Zeitintervall
const posts = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 }, // 1 Stunde
})
// ✅ Nie cachen für User-spezifische Daten
const user = await fetch('https://api.example.com/user', {
cache: 'no-store',
})
Route-Segment Config
// app/blog/page.tsx
export const revalidate = 3600 // Revalidate every hour
export const dynamic = 'force-static' // Force static generation
export const fetchCache = 'default-cache'
export default async function BlogPage() {
const posts = await getPosts()
return <PostList posts={posts} />
}
Client-Side Caching
'use client'
import { cache } from 'react'
// ✅ React Cache für Request Deduplication
const getUser = cache(async (id: string) => {
const res = await fetch(`/api/users/${id}`)
return res.json()
})
export function UserProfile({ userId }) {
// Wird nur 1x geladen, auch bei multiple calls
const user = use(getUser(userId))
return <div>{user.name}</div>
}
Tiefgehender in unserem Caching-Guide.
5. Bundle Analyzer nutzen
Visualisieren Sie Ihr Bundle:
# Installation
pnpm add -D @next/bundle-analyzer
# Konfiguration in next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({
// Ihre Next.js Config
})
# Ausführen
ANALYZE=true pnpm build
Achten Sie auf:
- Duplicate Dependencies (z.B. moment.js mehrfach)
- Große Packages die lazy geladen werden könnten
- Ungenutzte Exports (Tree-Shaking funktioniert nicht)
6. Server Components als Default
// ✅ Server Component (Default in App Router)
async function BlogPost({ slug }: { slug: string }) {
const post = await db.post.findUnique({ where: { slug } })
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
{/* Nur interaktive Teile als Client Component */}
<CommentSection postId={post.id} />
</article>
)
}
// components/CommentSection.tsx
'use client'
export function CommentSection({ postId }: { postId: string }) {
const [comments, setComments] = useState([])
// Interaktive Logik hier
}
Bundle-Reduktion: Server Components sind 0 KB im Client Bundle.
7. Parallele Datenladung
// ❌ Schlecht: Sequenziell (langsam!)
async function Dashboard() {
const user = await fetchUser() // 200ms
const posts = await fetchPosts() // 300ms
const analytics = await fetchAnalytics() // 500ms
// Total: 1000ms
}
// ✅ Gut: Parallel
async function Dashboard() {
const [user, posts, analytics] = await Promise.all([
fetchUser(), // \
fetchPosts(), // } Parallel - 500ms total
fetchAnalytics(), // /
])
}
// ✅ Noch besser: Mit Suspense
export default function Dashboard() {
return (
<div>
<Suspense fallback={<UserSkeleton />}>
<UserProfile />
</Suspense>
<Suspense fallback={<PostsSkeleton />}>
<PostsList />
</Suspense>
<Suspense fallback={<AnalyticsSkeleton />}>
<Analytics />
</Suspense>
</div>
)
}
8. Streaming mit Suspense
Progressive Rendering für bessere Perceived Performance:
import { Suspense } from 'react'
export default function Page() {
return (
<div>
{/* Kritischer Content lädt sofort */}
<Header />
{/* Nicht-kritischer Content streamt nach */}
<Suspense fallback={<Skeleton />}>
<SlowComponent />
</Suspense>
<Suspense fallback={<Skeleton />}>
<AnotherSlowComponent />
</Suspense>
<Footer />
</div>
)
}
Ergebnis:
- ⚡ FCP verbessert sich um 40-60%
- 🎯 User sieht Content sofort
- 🚀 Keine leeren Seiten mehr
9. Metadata für besseres SEO
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next'
export async function generateMetadata({
params,
}: {
params: { slug: string }
}): Promise<Metadata> {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [{ url: post.image, width: 1200, height: 630 }],
type: 'article',
publishedTime: post.publishedAt,
authors: [post.author.name],
},
twitter: {
card: 'summary_large_image',
title: post.title,
description: post.excerpt,
images: [post.image],
},
alternates: {
canonical: `https://headon.pro/blog/${post.slug}`,
},
}
}
10. Route Handlers für API Optimization
// app/api/posts/route.ts
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const limit = searchParams.get('limit') || '10'
const posts = await db.post.findMany({
take: parseInt(limit),
select: {
id: true,
title: true,
slug: true,
// ✅ Selektiere nur benötigte Felder
// NICHT: content (kann sehr groß sein)
},
})
return NextResponse.json(posts, {
headers: {
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400',
},
})
}
11. Third-Party Scripts optimieren
import Script from 'next/script'
export default function Page() {
return (
<>
{/* ✅ Analytics mit afterInteractive */}
<Script
src="https://www.googletagmanager.com/gtag/js?id=GA_ID"
strategy="afterInteractive"
/>
{/* ✅ Chat Widget mit lazyOnload */}
<Script
src="https://widget.example.com/chat.js"
strategy="lazyOnload"
/>
{/* ✅ Critical Scripts mit beforeInteractive */}
<Script
src="/critical-polyfill.js"
strategy="beforeInteractive"
/>
</>
)
}
Strategy-Guide:
beforeInteractive
: Nur für kritische PolyfillsafterInteractive
: Standard für AnalyticslazyOnload
: Chat-Widgets, Social Media
12. Database Query Optimization
// ❌ N+1 Query Problem
async function getBlogPosts() {
const posts = await db.post.findMany()
for (const post of posts) {
post.author = await db.user.findUnique({ where: { id: post.authorId } })
post.comments = await db.comment.findMany({ where: { postId: post.id } })
}
// 1 + 2N Queries!
}
// ✅ Single Query mit Includes
async function getBlogPosts() {
const posts = await db.post.findMany({
include: {
author: true,
comments: {
take: 5, // Nur neueste 5
orderBy: { createdAt: 'desc' },
},
},
})
// Nur 1 Query!
}
13. Edge Runtime für globale Performance
// app/api/edge-example/route.ts
export const runtime = 'edge'
export async function GET(request: Request) {
// Läuft auf Edge Runtime (CloudFlare Workers, etc.)
// Näher am User = schnellere Response
return new Response('Hello from the Edge!')
}
Vorteile:
- ⚡ 30-50% schnellere Response global
- 🌍 Ausführung am nächsten Edge-Location
- 📦 Kleinere Bundles (Edge-optimiert)
Limitations:
- Kein Node.js APIs (fs, child_process)
- Limitierte NPM-Packages
- Max 1MB Code-Size
14. Monitoring & Messung
Web Vitals tracken
// app/layout.tsx
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Script
src="https://analytics.yourdomain.com/script.js"
data-website-id="your-umami-website-id"
strategy="afterInteractive"
/>
</body>
</html>
)
}
Custom Metrics
'use client'
import { useReportWebVitals } from 'next/web-vitals'
export function WebVitals() {
useReportWebVitals((metric) => {
console.log(metric)
// An Analytics senden
if (metric.label === 'web-vital') {
window.gtag('event', metric.name, {
value: Math.round(metric.value),
event_label: metric.id,
non_interaction: true,
})
}
})
return null
}
Mehr zu Core Web Vitals in unserem Guide.
15. Production-Build optimieren
// next.config.js
module.exports = {
// ✅ Compression aktivieren
compress: true,
// ✅ React Production Mode
reactStrictMode: true,
// ✅ Source Maps für Production (optional)
productionBrowserSourceMaps: false,
// ✅ Compiler-Optimierungen
compiler: {
removeConsole: {
exclude: ['error', 'warn'], // console.log entfernen
},
},
// ✅ Experimental Features
experimental: {
optimizeCss: true, // CSS Optimization
optimizePackageImports: ['lucide-react', 'date-fns'], // Package Imports
},
// ✅ Output-Optimierung
output: 'standalone', // Für Docker
}
Performance Checklist
Vor jedem Production-Deployment:
- [ ] Lighthouse Score 90+ (Desktop & Mobile)
- [ ] LCP < 2.5s (idealerweise < 1.0s)
- [ ] FID < 100ms
- [ ] CLS < 0.1
- [ ] All images mit
next/image
- [ ] Fonts mit
next/font
optimiert - [ ] Bundle Analyzer gecheckt
- [ ] Keine console.logs in Production
- [ ] Cache-Headers konfiguriert
- [ ] Sitemaps generiert
- [ ] Monitoring aktiviert
Real-World Ergebnisse
Bei unserem E-Commerce-Projekt:
Vor Optimierung:
- LCP: 3.2s
- FCP: 1.8s
- Bundle: 456 KB
- Lighthouse: 67
Nach Optimierung:
- LCP: 0.9s ✅ (-72%)
- FCP: 0.4s ✅ (-78%)
- Bundle: 198 KB ✅ (-57%)
- Lighthouse: 98 ✅ (+46%)
Business Impact:
- +23% Conversion Rate
- -35% Bounce Rate
- +15% Average Session Duration
Häufige Performance-Killer
1. Unoptimierte Images
// ❌ Direktes <img> Tag
<img src="/large-image.jpg" />
// ✅ next/image
<Image src="/large-image.jpg" width={800} height={600} />
2. Blocking Scripts
// ❌ Synchrones Script
<script src="https://cdn.example.com/widget.js"></script>
// ✅ Next.js Script mit Strategy
<Script src="https://cdn.example.com/widget.js" strategy="lazyOnload" />
3. Große Dependencies
// ❌ Gesamte Library importieren
import _ from 'lodash' // 70 KB!
// ✅ Nur benötigte Funktionen
import debounce from 'lodash/debounce' // 2 KB
Tools für Performance-Testing
- Lighthouse - Chrome DevTools
- WebPageTest - webpagetest.org
- PageSpeed Insights - pagespeed.web.dev
- Umami Analytics - Real User Monitoring (selbstgehostet)
- Bundle Analyzer - Webpack Bundle Visualisierung
Zusammenfassung
Next.js Performance-Optimierung ist systematisch:
- ✅ Images mit next/image optimieren
- ✅ Fonts mit next/font selbst hosten
- ✅ Code-Splitting mit dynamic imports
- ✅ Caching aggressiv nutzen
- ✅ Server Components als Default
- ✅ Parallele Datenladung implementieren
- ✅ Monitoring einrichten
Ergebnis: Lighthouse 90+, LCP < 1.0s, glücklichere User.
Performance-Audit gefällig?
Als Performance-Spezialisten analysieren wir Ihre Next.js-App:
- 🔍 Detaillierter Performance-Report
- 🎯 Konkrete Optimierungsvorschläge
- 🚀 Implementierungs-Roadmap
- 📊 Vorher/Nachher Metriken
Weitere Ressourcen
Aktualisiert: September 2024