Nextjs Metadata SEO Route Groups Layouts Loading Error UI
Definisi
Di App Router, beberapa file khusus mengatur cara Next.js merender halaman, membangun <head>, dan menangani transisi antar-route. Topik yang paling sering dipakai adalah:
- metadata: informasi halaman seperti title, description, canonical, Open Graph, robots, dan icon
- SEO: dampak metadata dan struktur render terhadap keterbacaan mesin pencari dan preview sosial
- route groups: folder berkurung
(...)untuk mengelompokkan struktur tanpa mengubah URL - layout: kerangka UI yang dibagikan lintas halaman
- loading UI: fallback saat segment sedang diproses atau sedang streaming
- error UI: fallback saat render gagal di segment tertentu
Kalau dipahami bersama, keenam hal ini membentuk cara Next.js mengatur pengalaman baca halaman dari request awal sampai navigasi antar-route.
Kapan dipakai
Pola ini relevan saat aplikasi mulai punya:
- beberapa halaman dengan metadata berbeda
- layout yang dibagi per area, misalnya marketing dan dashboard
- data dinamis yang butuh title/description berbeda per route
- loading state yang harus terasa instan saat pindah halaman
- error boundary yang tidak ingin menjatuhkan seluruh aplikasi
- struktur folder yang rapi tanpa ikut mengotori URL
Kalau aplikasi masih sangat kecil, semua konsep ini tetap bisa dipakai, tetapi manfaatnya paling terasa ketika struktur route mulai bertambah.
Cara kerja metadata di App Router
Next.js App Router tidak menunggu developer menulis tag <meta> secara manual di setiap halaman. Sebagai gantinya, Next.js membaca ekspor metadata dari layout.tsx atau page.tsx, lalu membangkitkan tag HTML yang diperlukan.
Ada dua pendekatan utama:
1. metadata statis
Pakai ini kalau nilainya sudah jelas di saat build atau tidak bergantung pada data runtime.
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Blog Hadie',
description: 'Catatan teknis tentang Next.js, React, dan web development.',
}Pendekatan ini cocok untuk:
- halaman statis
- root layout
- route yang metadata-nya jarang berubah
- default SEO untuk satu section aplikasi
2. generateMetadata dinamis
Pakai ini kalau metadata bergantung pada param route, data fetch, atau context segment di atasnya.
import type { Metadata } from 'next'
type Props = {
params: Promise<{ slug: string }>
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params
const post = await fetch(`https://example.com/api/posts/${slug}`).then((res) => res.json())
return {
title: post.title,
description: post.excerpt,
}
}Poin pentingnya:
generateMetadatahanya tersedia di Server Component- metadata bisa mengambil data route seperti
params - metadata dapat mewarisi nilai dari parent segment
- child segment bisa menimpa value parent jika key-nya sama
Cara Next.js merakit metadata
Urutannya berjalan dari root ke leaf segment. Artinya:
- root layout memberi default global
- layout level bawah menambahkan atau menimpa sebagian nilai
- page paling akhir menetapkan metadata paling spesifik
Jika beberapa segment mengisi key yang sama, nilai paling bawah menang. Karena itu, root layout biasanya dipakai untuk default global seperti title.template, metadataBase, dan description generik.
Metadata dan SEO
Metadata punya pengaruh langsung ke SEO dan share preview:
titlemembantu identifikasi halaman di hasil pencarian dan tab browserdescriptionsering dipakai untuk cuplikan hasil pencarianopenGraphdantwittermemengaruhi kartu saat link dibagikanrobotsmengatur apakah halaman boleh diindeksalternatesmembantu canonical dan bahasa alternatif
Namun SEO di App Router bukan cuma soal metadata. Struktur render juga ikut menentukan kualitas halaman:
- HTML awal yang sudah berisi konten membantu crawling
- layout yang konsisten memudahkan navigasi dan pemeliharaan
- loading dan error UI menjaga pengalaman saat data belum siap atau gagal
File-based metadata
Selain ekspor metadata dan generateMetadata, Next.js juga mendukung file khusus seperti:
favicon.icoicon.pngapple-icon.pngopengraph-image.tsxrobots.txtsitemap.xml
Ini berguna kalau aset metadata lebih enak dikelola sebagai file daripada konfigurasi kode.
Kapan layout dipakai
Layout dipakai ketika ada UI yang harus dibagikan oleh beberapa page dan tidak perlu diganti total setiap navigasi.
Contoh penggunaan layout:
- navbar global
- sidebar dashboard
- footer konsisten
- shell autentikasi
- wrapper konten per section
Peran layout
Layout adalah kerangka, bukan isi final halaman. Ia menerima children dan membungkus page atau nested layout di bawahnya.
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="dashboard-shell">
<aside>Sidebar</aside>
<main>{children}</main>
</div>
)
}Kapan layout lebih tepat daripada page
Pakai layout jika:
- UI-nya harus tetap hidup lintas navigasi
- state di shell perlu dipertahankan
- ada struktur visual yang sama untuk banyak route
- kamu ingin route turunan tetap terasa sebagai satu area
Pakai page jika:
- isinya spesifik untuk satu route
- komponen itu tidak perlu dibagikan ke sibling route
- UI-nya berubah total ketika URL berganti
Efek praktis layout
Di App Router, layout membantu:
- menjaga state shell saat navigasi internal
- mengurangi duplikasi markup
- memisahkan concerns antar-section
- memberi tempat yang tepat untuk metadata default dan struktur HTML global
Catatan penting: root layout wajib memuat <html> dan <body>.
Route groups dan pengaruhnya terhadap URL
Route group ditulis dengan folder berkurung, misalnya:
app/
(marketing)/
about/
page.tsx
(dashboard)/
settings/
page.tsxFolder (marketing) dan (dashboard) dipakai untuk organisasi kode, tetapi tidak muncul di URL.
Hasil route-nya tetap:
app/(marketing)/about/page.tsx→/aboutapp/(dashboard)/settings/page.tsx→/settings
Kapan route group berguna
Route groups berguna untuk:
- memisahkan area aplikasi berdasarkan domain bisnis
- menaruh layout yang berbeda per area
- menjaga folder tetap rapih tanpa memaksa path URL ikut berubah
- menghindari folder root yang terlalu padat
Batasan penting
Ada dua hal yang perlu diingat:
- route dari group berbeda tidak boleh menghasilkan URL yang sama
- kalau menggunakan beberapa root layout, perpindahan antar root layout bisa memicu full page load
Artinya, route groups memang membantu organisasi, tetapi tetap harus dirancang bersama struktur layout dan URL yang konsisten.
Loading UI dan pengalaman pengguna
File loading.tsx atau loading.js dipakai untuk memberi fallback UI saat sebuah route segment sedang diproses.
export default function Loading() {
return <p>Memuat halaman…</p>
}Cara kerja loading UI
Di App Router, loading.tsx otomatis membungkus page segment dengan Suspense boundary. Begitu segment belum siap, Next.js bisa menampilkan fallback lebih cepat tanpa menunggu seluruh page selesai.
Ini penting untuk:
- memberi sinyal bahwa navigasi sedang berlangsung
- mengurangi kesan halaman macet
- mendukung streaming UI
- menjaga interaksi terasa responsif
Loading UI yang baik
Loading UI sebaiknya ringan:
- skeleton
- placeholder teks
- shimmer sederhana
- state yang jelas namun tidak berlebihan
Jangan gunakan loading screen yang berat kalau tujuan utamanya hanya memberi jeda singkat. Idealnya loading UI membantu user tetap yakin bahwa aplikasi masih bekerja.
Error UI dan pemulihan lokal
File error.tsx atau error.js dipakai untuk menangkap error pada segment tertentu dan menampilkan fallback yang lebih ramah.
'use client'
export default function Error(
{ error,
reset }: { error: Error & { digest?: string },
reset: () => void }
) {
return (
<div>
<h2>Terjadi masalah</h2>
<p>{error.message}</p>
<button onClick={() => reset()}>Coba lagi</button>
</div>
)
}Peran error UI
Error UI menjaga agar kegagalan tidak langsung menjatuhkan seluruh aplikasi. Dengan boundary di level route segment:
- error bisa diisolasi
- user masih bisa retry
- area lain di aplikasi tetap berjalan
- debugging lebih mudah karena batas segment lebih jelas
Kapan error UI dibutuhkan
Gunakan error boundary saat:
- page bergantung pada data eksternal
- ada kemungkinan fetch gagal
- ada interaksi yang bisa menghasilkan runtime error
- kamu ingin fallback spesifik per area, bukan layar error global
Alur render dan layout
Secara sederhana, alurnya seperti ini:
Diagram ini menunjukkan tiga hal penting:
- route group hanya mengatur struktur, bukan URL
- layout membungkus page dan bisa dipertahankan antar navigasi
- loading/error UI adalah lapisan pengalaman pengguna, bukan sekadar pelengkap
Contoh struktur folder
app/
layout.tsx
page.tsx
(marketing)/
layout.tsx
about/
page.tsx
loading.tsx
error.tsx
(dashboard)/
layout.tsx
settings/
page.tsxCara membacanya:
app/layout.tsx= root shell global(marketing)/layout.tsx= shell khusus area marketing(dashboard)/layout.tsx= shell khusus area dashboardloading.tsx= fallback saat page segment sedang diproseserror.tsx= fallback saat segment gagal render
Catatan implementasi
- Gunakan
metadatastatis untuk default global dan halaman yang tidak bergantung data runtime. - Gunakan
generateMetadatauntuk route dinamis yang title/description-nya datang dari data. - Letakkan metadata umum di root layout, lalu override di page atau layout turunan bila perlu.
- Pakai layout untuk UI yang harus persist lintas navigasi.
- Pakai route group untuk merapikan struktur tanpa mengubah URL.
- Pakai
loading.tsxuntuk fallback ringan, bukan untuk mengganti seluruh page dengan layar yang berat. - Pakai
error.tsxuntuk mengisolasi kegagalan per segment agar user tetap bisa recovery. - Kalau route group berbeda menghasilkan URL yang sama, perbaiki struktur sebelum lanjut.
Jebakan umum
- Menaruh metadata dinamis di client component. Ini tidak didukung.
- Membuat layout terlalu gemuk sampai semua fetch pindah ke sana.
- Mengira route group akan menambah prefix URL. Tidak.
- Mengabaikan bahwa beberapa root layout bisa memicu full reload antar area.
- Membuat loading UI terlalu kompleks sehingga malah terasa lebih lambat.
- Tidak menyediakan tombol retry pada error boundary.
Referensi singkat
metadatadangenerateMetadata- file-based metadata seperti
opengraph-imagedansitemap.xml layout.tsxuntuk shell yang dibagikan- route groups
(folder)untuk organisasi tanpa perubahan URL loading.tsxuntuk Suspense fallbackerror.tsxuntuk error boundary segment
Ringkasnya
Kalau harus dipadatkan:
- metadata dipakai untuk SEO dan share preview
- layout dipakai untuk UI bersama yang harus bertahan lintas halaman
- route groups dipakai untuk struktur folder tanpa mengubah URL
- loading UI dipakai untuk membuat transisi terasa cepat
- error UI dipakai untuk isolasi kegagalan dan pemulihan lokal
Itu kombinasi dasar yang biasanya paling berguna saat membangun App Router yang rapi dan enak dipakai harian.