optimasi-performa-nextjs
Fapskom IT
Published
Optimasi Performa Next.js: Dari Cukup Baik ke Super Cepat
Next.js hadir dengan berbagai fitur performa bawaan yang sangat mumpuni, tetapi memahami cara kerja serta bagaimana melakukan konfigurasi yang tepat adalah kunci utama untuk menghadirkan aplikasi web yang luar biasa cepat dan responsif. Panduan ini membahas strategi paling berdampak untuk optimasi Next.js di tahun 2026.
1. Gunakan React Server Components (RSC)
Optimasi paling krusial pada Next.js modern adalah memindahkan logika pengambilan data (data fetching) ke Server Components. Karena komponen ini dirender di server, tidak ada JavaScript dari Server Components tersebut yang perlu dikirim ke browser pengguna.
// app/blog/page.tsx — Secara default merupakan Server Component
// Tanpa arahan 'use client' = dijalankan murni di server
async function getPosts() {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 }, // Validasi ulang setiap jam
});
return res.json();
}
export default async function BlogPage() {
const posts = await getPosts(); // async/await langsung — tanpa useEffect!
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Keuntungan yang Anda dapatkan:
- Tidak ada JavaScript di sisi klien untuk proses pengambilan data.
- Ukuran bundel (bundle size) aplikasi menjadi jauh lebih kecil.
- Time to First Byte (TTFB) menjadi lebih cepat.
- Akses langsung ke database, sistem file (file system), dan kredensial/rahasia API yang aman.
2. Penggunaan use client Secara Bijak
Tidak semua komponen harus berupa Client Component. Hanya tambahkan arahan 'use client' jika Anda membutuhkan:
- API bawaan browser (
window,document,localStorage) - React hook (
useState,useEffect,useContext) - Event listener (seperti
onClick,onChange)
// ✅ BENAR: letakkan interaktivitas di komponen ujung daun (leaf components)
'use client';
import { useState } from 'react';
export function LikeButton({ postId }: { postId: string }) {
const [liked, setLiked] = useState(false);
return (
<button onClick={() => setLiked(!liked)}>
{liked ? '❤️ Disukai' : '🤍 Suka'}
</button>
);
}
// ❌ SALAH: mengubah satu halaman penuh menjadi sisi klien hanya untuk satu interaksi
'use client';
import { useState, useEffect } from 'react';
export default function BlogPage() {
// Sekarang SEMUA data fetching berpindah ke klien — menjadi lebih lambat!
const [posts, setPosts] = useState([]);
useEffect(() => { fetch('/api/posts').then(...) }, []);
// ...
}
3. Optimasi Gambar dengan next/image
Komponen <Image> dari next/image secara otomatis melakukan:
- Menyajikan gambar dalam format modern seperti WebP/AVIF
- Menggunakan lazy loading (pemuatan tertunda) secara default
- Mencegah pergeseran tata letak halaman (Cumulative Layout Shift - CLS) dengan mewajibkan atribut
widthdanheight
import Image from 'next/image';
export function ArticleHero({ src, alt }: { src: string; alt: string }) {
return (
<Image
src={src}
alt={alt}
width={1200}
height={630}
priority // Gunakan untuk gambar di atas lipatan layar (LCP element)
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AA..." // Pratinjau base64 kecil
/>
);
}
Properti kunci:
priority— Menonaktifkan lazy loading; sangat direkomendasikan untuk elemen Largest Contentful Paint (LCP).sizes— Menginstruksikan browser ukuran gambar yang sesuai berdasarkan breakpoint perangkat.quality— Nilai default adalah 75; Anda dapat mengaturnya lebih rendah untuk latar belakang, atau lebih tinggi untuk gambar utama.
4. Optimasi Font
Modul next/font mengeliminasi pergeseran tata letak saat memuat font (layout shift) dan menghapus permintaan jaringan eksternal untuk privasi dan kecepatan yang lebih baik:
import { Inter, JetBrains_Mono } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
display: 'swap',
});
const mono = JetBrains_Mono({
subsets: ['latin'],
variable: '--font-mono',
display: 'swap',
});
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html className={`${inter.variable} ${mono.variable}`}>
<body>{children}</body>
</html>
);
}
5. Pemisahan Kode dengan next/dynamic
Pustaka (library) berukuran besar sebaiknya tidak disertakan dalam bundel awal JavaScript Anda. Gunakan impor dinamis untuk memuatnya saat diperlukan saja:
import dynamic from 'next/dynamic';
// Pustaka grafik yang berat hanya akan dimuat ketika komponen <Chart> dirender
const Chart = dynamic(() => import('./Chart'), {
loading: () => <div className="h-64 animate-pulse bg-neutral-800 rounded-xl" />,
ssr: false, // Set false untuk pustaka yang hanya berjalan di browser
});
export function Dashboard() {
return (
<section>
<h2>Analitik</h2>
<Chart />
</section>
);
}
6. Strategi Caching
Next.js memberi Anda kontrol granular terhadap strategi caching data:
// Statis — disimpan secara permanen (default untuk rute statis)
export const dynamic = 'force-static';
// Validasi ulang setiap 60 detik (Incremental Static Regeneration - ISR)
export const revalidate = 60;
// Jangan pernah disimpan di cache — selalu ambil data baru saat dipanggil
export const dynamic = 'force-dynamic';
Untuk panggilan fetch individual:
// Simpan cache selama 1 jam
const data = await fetch('/api/data', { next: { revalidate: 3600 } });
// Jangan gunakan cache sama sekali
const data = await fetch('/api/data', { cache: 'no-store' });
// Revalidasi berbasis tag (sangat kuat)
const data = await fetch('/api/posts', { next: { tags: ['posts'] } });
// Kemudian: jalankan revalidateTag('posts') untuk memperbarui cache
7. Analisis Bundel (Bundle Analysis)
Sebelum Anda melakukan optimasi, lakukan pengukuran terlebih dahulu. Instal pustaka @next/bundle-analyzer:
npm install @next/bundle-analyzer
// next.config.ts
import bundleAnalyzer from '@next/bundle-analyzer';
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
});
export default withBundleAnalyzer(nextConfig);
Jalankan build dengan analisis bundel aktif:
ANALYZE=true npm run build
8. Checklist Core Web Vitals
| Metrik | Target | Penyebab Utama Kegagalan |
|---|---|---|
| LCP (Largest Contentful Paint) | < 2.5s | Gambar tidak dioptimalkan, respons server lambat |
| CLS (Cumulative Layout Shift) | < 0.1 | Tidak mencantumkan width/height pada gambar |
| INP (Interaction to Next Paint) | < 200ms | Logika JS yang berat pada main thread |
| TTFB (Time to First Byte) | < 800ms | Pengambilan data lambat, tidak menggunakan caching |
9. Streaming dengan Suspense
Jangan biarkan proses pengambilan data yang lambat menghalangi seluruh halaman untuk dimuat. Stream bagian-bagian UI tertentu menggunakan Suspense:
import { Suspense } from 'react';
export default function Page() {
return (
<main>
<h1>Dasbor Utama</h1> {/* Langsung dirender */}
<Suspense fallback={<StatsSkeletonLoader />}>
<SlowStatsComponent /> {/* Dimuat secara terpisah saat siap */}
</Suspense>
</main>
);
}
Kesimpulan
Performa unggul di Next.js adalah hasil dari penggabungan berbagai keputusan arsitektur yang cermat:
- Gunakan Server Components secara default — hanya gunakan
'use client'ketika interaktivitas benar-benar dibutuhkan. - Gunakan
next/imageuntuk semua file gambar — hindari tag biasa<img>. - Gunakan
next/fontuntuk semua font khusus. - Impor secara dinamis (
next/dynamic) pustaka yang berukuran besar. - Terapkan kebijakan cache yang sesuai pada setiap rute dan fetch.
- Stream UI yang lambat dengan pembatas Suspense.
- Ukur performa secara berkala menggunakan
@next/bundle-analyzerdan Chrome DevTools.
Penerapan konsisten dari pola-pola ini akan menaikkan nilai Lighthouse Anda di atas 95, dan para pengguna Anda akan sangat menyukainya! ⚡