# Cara Membuat SEO Metadata Next.js App Router untuk Pemula

> Cara membuat SEO metadata Next.js App Router untuk pemula: generateMetadata, canonical, hreflang, Open Graph, sitemap.ts, robots.ts, plus error umum.

URL: https://www.matthewswong.com/id/blog/cara-membuat-seo-metadata-nextjs-app-router/

- Author: Matthews Wong (https://www.matthewswong.com/id/about/)
- Published: 2026-10-17
- Updated: 2026-10-17
- Category: Web Dev

> **Key takeaway:** Cara membuat SEO metadata di Next.js App Router: atur metadataBase dan title template di root layout, lalu ekspor generateMetadata di tiap page berisi title, description, canonical, alternate hreflang, dan objek openGraph yang mengulang semua field yang ingin dibagikan. Tambahkan sitemap.ts dan robots.ts, lalu baca HTML hasil build untuk memastikannya.

Kamu membuka view source situs Next.js yang baru jadi, dan di head hanya ada satu title tanpa yang lain. Atau kamu menambahkan title di layout, lalu semua halaman menampilkan title yang sama. Atau kartu bagikan di WhatsApp judulnya benar tetapi gambarnya hilang. Pemula biasanya tersangkut di salah satu dari tiga hal ini, karena Metadata API-nya kecil tetapi aturan penggabungannya tidak kelihatan.

Panduan ini membangun metadata satu halaman dua bahasa dalam enam langkah. Setiap nama field dan bentuk kode saya cocokkan dengan dokumentasi Next.js dan Google Search Central, dan contohnya memakai example.com sebagai placeholder. Pola yang sama dipakai situs ini: satu helper di lib/seo.ts membangun semua URL canonical dan hreflang, dan tag head serta sitemap sama-sama membacanya, jadi keduanya tidak bisa berbeda.

Mau memahami konsepnya dulu, termasuk JSON-LD dan alasan tiap tag ada? Ikuti pelajaran gratis

Tutorial SEO Metadata Next.js: generateMetadata sampai JSON-LD

di jalur Web app skills. Post ini adalah praktik langkah demi langkahnya.

Yang kamu butuhkan

Proyek Next.js dengan App Router (folder app), memakai TypeScript.

Sebuah route dengan segmen locale, misalnya app/[locale]/guide/page.tsx. Kalau situsmu satu bahasa, abaikan bagian locale.

Node.js dan terminal, untuk menjalankan build produksi dan membaca HTML yang sebenarnya dengan curl.

Alamat situs aslimu. Panduan ini memakai https://example.com sebagai pengganti.

Belum menyiapkan dua bahasa? Baca dulu

panduan next-intl untuk i18n Next.js

, lalu kembali ke sini untuk metadatanya.

## Langkah 1: Bangun URL absolut dari satu helper

Mulai dari bagian yang dipakai ulang oleh semua langkah berikutnya: helper yang mengembalikan URL canonical dan hreflang yang absolut. Taruh di lib/seo.ts. Menulis URL manual di tiap page adalah cara versi Inggris dan Indonesia akhirnya saling menunjuk dengan salah.

Lalu atur metadataBase dan title template satu kali, di root layout. Menurut dokumentasi, path relatif di field URL tanpa metadataBase menyebabkan error build, dan title.template berlaku untuk segmen anak tetapi tidak untuk segmen yang mendefinisikannya, karena itu title.default wajib ada bersamanya.

Belum ada output yang perlu dilihat. Buktinya muncul di Langkah 6. Page yang mengatur title sebagai string biasa kini mendapat ekor merek dari template; page yang tidak mengatur title mendapat title.default.

## Langkah 2: Ekspor generateMetadata dari page

Pakai objek metadata tetap kalau nilainya tidak berubah, dan fungsi async generateMetadata kalau nilainya bergantung pada params route atau data. Di Next.js 15, params berupa Promise, jadi kamu await. Keduanya hanya bekerja di Server Component, dan tidak boleh diekspor bersamaan dari segmen yang sama.

Jangan menambahkan use client pada page yang mengekspor metadata. Biarkan page tetap Server Component dan pindahkan bagian interaktifnya ke file sendiri, seperti saran dokumentasi.

Title di sini memakai bentuk absolute, dengan merek yang sudah ditulis di dalamnya. Langkah berikutnya mengisi alternates. Kalau kamu mengambil data di dalam generateMetadata, dokumentasi menyebut fetch yang identik di-memoize antara generateMetadata, layout, dan page, jadi page sendiri bisa meminta data yang sama tanpa request kedua.

## Langkah 3: Tambahkan canonical dan hreflang untuk tiap bahasa

Setiap versi bahasa menyebut dirinya sendiri sebagai canonical, dan alternates.languages mencantumkan semua versi. Google menyatakan setiap versi harus mencantumkan dirinya sendiri dan semua versi lain, tautannya harus timbal balik atau tag-nya diabaikan, dan URL harus lengkap (fully qualified). Google menyarankan path absolut pada elemen canonical dan canonical yang menunjuk ke dirinya sendiri pada halaman canonical.

Entri x-default adalah cadangan untuk pengunjung yang bahasanya tidak cocok dengan versi mana pun. Situs ini mengarahkannya ke halaman Inggris. Karena kedua sisi berasal dari fungsi yang sama, aturan timbal balik tidak bisa rusak karena salah ketik.

Google menganggap tiga cara menyatakan alternate, yaitu tag link HTML, header HTTP, dan sitemap, setara, jadi satu sudah cukup. Panduan ini memakai tag link dan juga mengisinya di sitemap pada Langkah 5.

## Langkah 4: Tambahkan Open Graph dan Twitter tanpa kehilangan field

Tag Open Graph dan Twitter mengatur pratinjau tautan. Atur openGraph dengan title, description, url, type, dan images, serta twitter.card ke summary_large_image untuk pratinjau besar. Dokumentasi menandai URL gambar harus absolut.

Metadata digabung secara dangkal (shallow). Kalau layout mengatur openGraph dengan description dan gambar, lalu page mengatur openGraph hanya dengan title, kartu page itu hanya punya title. Seluruh objek diganti, bukan digabung.

Solusinya adalah menarik field bersama ke satu objek lalu menyebarkannya (spread) ke tiap segmen, seperti pola di dokumentasi. Untuk gambar unik per halaman, lihat

pembuatan OG image dinamis di Next.js

Aplikasi sosial menyimpan cache pratinjau, jadi kartu yang masih salah setelah tag diperbaiki bisa jadi hanya salinan lama.

## Langkah 5: Buat sitemap.ts dan robots.ts

app/sitemap.ts mengembalikan array entri, masing-masing dengan url serta lastModified dan alternates.languages yang opsional (dukungan lokalisasi hadir di Next.js 14.2). Pakai ulang helper Langkah 1 agar sitemap sepakat dengan tag head. File ini disajikan sebagai /sitemap.xml.

app/robots.ts mengembalikan rules dengan userAgent, allow, dan disallow, plus alamat sitemap. Kedua file adalah Route Handler khusus yang di-cache secara default kecuali memakai API waktu-request. Jaga lastModified tetap jujur: pakai tanggal konten benar-benar berubah, bukan new Date() di setiap build.

Beginilah bentuk robots.txt hasil generate untuk contoh di atas, mengikuti format output di dokumentasi.

## Langkah 6: Periksa HTML hasil build, bukan source-nya

Source code bisa terlihat benar padahal halaman mengirim hal lain, karena title template dan penggabungan terjadi saat build. Jalankan build produksi, start, lalu baca respons yang sebenarnya dengan curl. Periksa halaman Indonesia, bukan hanya yang Inggris.

Cari empat hal: satu title dengan ekor merek tepat satu kali, canonical berupa URL halaman itu sendiri dalam bahasanya sendiri, satu link hreflang per bahasa plus x-default, dan og:image yang diawali https. Urutan atribut persisnya bisa berbeda dari dugaanmu, jadi cocokkan berdasarkan nama tag.

Kalau ada tag yang hilang di sini, tidak ada tool lain yang akan memperbaikinya. Kembali ke langkah yang mengurusnya.

Error umum dan cara memperbaikinya

Kebanyakan kesalahan metadata gagal tanpa suara: build lolos dan hanya outputnya yang salah. Tabel ini memetakan gejala yang kamu lihat ke penyebabnya.

Gejala

Penyebab

Perbaikan

Build gagal di field URL metadata

Dipakai path relatif seperti /og.png dan metadataBase belum diatur.

Atur metadataBase ke new URL milik situsmu di root layout, atau tulis URL absolut.

Title halaman anak tidak punya ekor merek

Template didefinisikan di segmen yang sama dengan title, atau segmen parent hanya mengatur title absolute tanpa template sendiri.

Definisikan template di layout parent, dan pakai satu mode per subtree. Periksa HTML hasil build.

Merek muncul dua kali di title

Title sudah berakhir dengan merek dan template di root menambahkannya lagi.

Pakai title.absolute pada halaman yang titlenya sudah memuat merek. Situs ini melakukannya untuk setiap halaman yang panjang titlenya diatur.

Kartu bagikan kehilangan gambar atau description

Sebuah page mengatur openGraph, sehingga mengganti seluruh objek openGraph milik layout.

Spread objek bersama ke openGraph tiap segmen, atau ulangi field yang masih diinginkan.

Google mengabaikan hreflang saya

Tautannya tidak timbal balik, sebuah versi tidak mencantumkan dirinya sendiri, atau URL-nya relatif.

Hasilkan alternate semua bahasa dari satu fungsi dan jaga URL tetap absolut.

Canonical halaman Indonesia menunjuk ke halaman Inggris

URL Inggris disalin sebagai canonical untuk semua bahasa.

Setiap bahasa menyebut URL-nya sendiri sebagai canonical, dan hreflang yang menghubungkan versi-versinya.

Error saat mengekspor metadata

Page memakai use client, atau mengekspor metadata dan generateMetadata sekaligus.

Biarkan page tetap Server Component, pindahkan interaktivitas ke file terpisah, dan ekspor hanya salah satu dari keduanya.

Checklist

metadataBase dan title template beserta default diatur satu kali di root layout.

Setiap page mengekspor salah satu dari metadata atau generateMetadata, dari Server Component.

URL canonical dan hreflang berasal dari satu helper, absolut, dan tiap bahasa menyebut dirinya sendiri.

openGraph di-spread dari objek bersama atau diulang penuh, dengan URL gambar absolut.

sitemap.ts dan robots.ts ada, dan robots.ts menyebut alamat sitemap.

Kamu sudah membaca HTML hasil build halaman Indonesia dengan curl dan melihat tiap tag satu kali.

Belajar lebih dalam

Post ini adalah jalur praktiknya. Pelajaran gratisnya menjelaskan kenapa tiap tag ada, menambahkan JSON-LD dari server component, dan menelusuri file nyata di balik situs ini, dengan kuis singkat di akhir.

Buka pelajarannya: Tutorial SEO Metadata Next.js

Aturan yang dibawa pulang: tentukan setiap URL satu kali, di satu helper, dan biarkan semua tag serta sitemap membacanya. Lalu periksa HTML hasil build, karena kesalahan yang penting di sini tidak pernah menggagalkan build.

## Sumber

- Dokumentasi Next.js: generateMetadata
- Dokumentasi Next.js: sitemap.xml
- Dokumentasi Next.js: robots.txt
- Google Search Central: versi terlokalisasi dan hreflang
- Google Search Central: URL canonical

## Source links

- https://nextjs.org/docs/app/api-reference/functions/generate-metadata
- https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap
- https://nextjs.org/docs/app/api-reference/file-conventions/metadata/robots
- https://developers.google.com/search/docs/specialty/international/localized-versions
- https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls

## FAQ

### Kenapa title halaman Next.js saya salah atau tanpa nama brand?

Next.js menerapkan title.template hanya ke segmen anak, bukan ke segmen yang mendefinisikannya. Layout parent yang hanya mengatur title absolute juga tidak meneruskan template. Definisikan template di layout parent, pakai title.absolute pada halaman yang sudah memuat brand, lalu periksa HTML hasil build.

### Kenapa gambar Open Graph hilang saat saya mengatur openGraph di page?

Metadata digabung secara shallow, jadi objek openGraph di page mengganti seluruh objek openGraph dari layout. Gambar dan description yang kamu deklarasikan di sana ikut hilang. Taruh field bersama di satu objek lalu spread ke tiap segmen, atau ulangi field-nya.

### Apakah metadataBase wajib di Next.js?

Wajib kalau ada field metadata berbasis URL yang memakai path relatif. Tanpanya, build Next.js gagal. Kalau semua URL kamu tulis sebagai string absolut, metadataBase tidak wajib, tetapi mengaturnya sekali di root layout adalah pengaman paling sederhana.

### Apakah canonical halaman Indonesia harus menunjuk ke halaman Inggris?

Tidak. Setiap versi bahasa sebaiknya menyebut URL-nya sendiri sebagai canonical, dan hreflang yang menghubungkan versi-versinya. Google menyarankan canonical yang menunjuk ke dirinya sendiri, dan mengabaikan hreflang yang tidak timbal balik atau URL-nya tidak lengkap.

### Bolehkah memakai sitemap.ts dan robots.ts alih-alih file statis?

Boleh. app/sitemap.ts dan app/robots.ts adalah Route Handler khusus yang mengembalikan objek bertipe, dan Next.js menyajikannya sebagai /sitemap.xml dan /robots.txt. Keduanya di-cache secara default kecuali memakai API waktu-request, jadi pakai ulang helper URL kamu di dalamnya.

---

- HTML version: https://www.matthewswong.com/id/blog/cara-membuat-seo-metadata-nextjs-app-router/
- English: https://www.matthewswong.com/en/blog/cara-membuat-seo-metadata-nextjs-app-router/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
