Sitemap.xml dan robots.txt dinamis di Next.js App Router dibuat lewat file
convention khusus, `app/sitemap.ts` dan `app/robots.ts`, masing-masing
mengekspor fungsi yang mengembalikan array/objek data dan otomatis
di-render Next.js menjadi response XML dan teks di `/sitemap.xml` serta
`/robots.txt` saat diakses browser atau crawler.

**Ringkasan cepat:**

1. `app/sitemap.ts` dan `app/robots.ts` adalah file convention Next.js App Router, bukan file statis di folder `public/`.
2. Sitemap sebaiknya di-map dari data konten nyata, dengan `lastModified` jujur dari tanggal konten berubah.
3. `rules` di robots.ts menerima banyak blok per user agent, jadi crawler AI bisa diizinkan eksplisit terpisah dari aturan umum.
4. Field `sitemap` di robots.ts otomatis menambahkan baris `Sitemap:` di akhir `robots.txt` yang dihasilkan.
5. Selalu validasi lewat akses langsung ke `/sitemap.xml`/`/robots.txt` setelah deploy, lalu submit sitemap ke Google Search Console.

## Apa Itu Sitemap.xml dan Robots.txt di Next.js App Router?

Keduanya termasuk kategori "Metadata Files" di Next.js App Router: file
dengan nama dan lokasi khusus yang ditangani otomatis oleh framework,
tanpa perlu route handler manual. Bedanya dengan meletakkan file
`sitemap.xml`/`robots.txt` statis di folder `public/`: versi `.ts` bisa
menghasilkan isi yang berubah mengikuti data nyata (jumlah artikel blog,
tanggal terakhir diubah) tanpa perlu di-edit manual setiap kali konten
baru ditambahkan.

<table>
  <thead>
    <tr>
      <th>Aspek</th>
      <th>Sitemap.xml</th>
      <th>Robots.txt</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Fungsi utama</td>
      <td>Daftar URL yang ingin diindeks, membantu crawler menemukan halaman lebih cepat</td>
      <td>Aturan akses, menentukan folder atau user agent mana yang boleh/tidak boleh crawl</td>
    </tr>
    <tr>
      <td>File convention Next.js</td>
      <td>`app/sitemap.ts`</td>
      <td>`app/robots.ts`</td>
    </tr>
    <tr>
      <td>Tipe return</td>
      <td>`MetadataRoute.Sitemap` (array entri URL)</td>
      <td>`MetadataRoute.Robots` (objek berisi `rules`)</td>
    </tr>
    <tr>
      <td>Field kunci</td>
      <td>`url`, `lastModified`, `changeFrequency`, `priority`</td>
      <td>`rules` (per user agent), `sitemap`</td>
    </tr>
  </tbody>
</table>

### Kenapa Tidak Cukup File Statis di Folder public/?

File statis di `public/sitemap.xml` bisa dipakai untuk situs dengan
halaman yang jarang berubah, tapi jadi beban manual begitu jumlah halaman
bertambah (artikel blog baru, proyek portofolio baru). File convention
`sitemap.ts` menghasilkan ulang daftar URL setiap build, mengikuti data
yang sama dengan yang dipakai untuk merender halaman itu sendiri,
sehingga sitemap tidak pernah ketinggalan dari konten yang benar-benar
ada.

## Bagaimana Cara Membuat Sitemap.xml Dinamis dengan sitemap.ts?

Buat file `app/sitemap.ts`, ekspor default function yang mengembalikan
array objek bertipe `MetadataRoute.Sitemap`:

```ts
// app/sitemap.ts
import type { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: "https://contoh-domain.com/",
      lastModified: new Date(),
      changeFrequency: "monthly",
      priority: 1,
    },
    {
      url: "https://contoh-domain.com/blog",
      lastModified: new Date(),
      changeFrequency: "daily",
      priority: 0.8,
    },
  ];
}
```

Untuk situs dengan koleksi konten (blog, portofolio, produk), pola yang
lebih tahan lama adalah memetakan (`.map()`) data konten yang sudah ada
menjadi entri sitemap, bukan menulis URL satu per satu. Situs ini sendiri
memakainya persis begitu di `app/sitemap.ts`: daftar artikel dan proyek
diambil lewat fungsi pembaca konten yang sama dipakai halaman blog/portofolio,
lalu di-map jadi entri sitemap dengan `lastModified` yang diambil dari
tanggal commit git atau tanggal artikel terbaru, bukan tanggal build,
supaya sitemap tidak mengklaim halaman "baru diubah" padahal isinya sama
persis dengan minggu lalu.

### Field Apa Saja yang Sebaiknya Diisi per URL?

`url` dan `lastModified` adalah yang paling berguna secara praktis.
`changeFrequency` dan `priority` boleh diisi tapi menurut dokumentasi
resmi Next.js keduanya hanya hint, mesin pencari besar seperti Google
tidak menjamin mengikutinya secara ketat. Untuk gambar per halaman
(artikel dengan cover image, proyek dengan galeri), entri sitemap juga
bisa menambahkan field `images` (Google image sitemap extension) supaya
image crawler bisa menemukan gambar tanpa perlu merender HTML halaman
lebih dulu.

## Bagaimana Cara Membuat Robots.txt Dinamis dengan robots.ts?

Buat file `app/robots.ts`, ekspor default function yang mengembalikan
objek bertipe `MetadataRoute.Robots`:

```ts
// app/robots.ts
import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      {
        userAgent: "*",
        allow: "/",
        disallow: ["/api/", "/admin"],
      },
      {
        userAgent: "GPTBot",
        allow: "/",
      },
    ],
    sitemap: "https://contoh-domain.com/sitemap.xml",
  };
}
```

`rules` menerima array, jadi bisa ada banyak blok aturan berbeda per user
agent dalam satu file. Pola ini yang dipakai untuk mengizinkan crawler AI
tertentu (GPTBot, ClaudeBot, PerplexityBot, dan sejenisnya) secara
eksplisit, terpisah dari aturan umum `userAgent: "*"` yang berlaku untuk
bot lain. Field `sitemap` di objek yang sama otomatis menambahkan baris
`Sitemap: <url>` di akhir file `robots.txt` yang dihasilkan, sehingga
crawler yang membaca robots.txt langsung tahu ke mana harus mencari daftar
URL lengkap.

Output `robots.ts` bukan format bebas buatan Next.js sendiri, melainkan
mengikuti standar lama yang sudah dipakai web secara umum. Menurut
dokumentasi resmi Next.js untuk file convention `robots.txt`:

> "Add or generate a robots.txt file that matches the Robots Exclusion
> Standard in the root of app directory to tell search engine crawlers
> which URLs they can access on your site." ([Next.js documentation, file
> convention `robots.txt`](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/robots)).

### Kenapa Mengizinkan Crawler AI Secara Eksplisit?

Default `userAgent: "*"` dengan `allow: "/"` sebenarnya sudah mengizinkan
semua bot termasuk crawler AI. Blok tambahan per bot berguna kalau situs
ingin tetap terbuka untuk crawler AI meski suatu saat aturan umum diperketat
(mis. menambahkan `disallow` baru untuk bot spam), atau sekadar sebagai
sinyal eksplisit yang mudah diaudit satu per satu tanpa harus menebak dari
aturan umum yang berlaku untuk banyak bot sekaligus.

Mengizinkan crawler AI di robots.txt hanya menentukan boleh-tidaknya akses,
belum tentu membantu AI agent memahami struktur konten begitu masuk. Untuk
itu ada file pelengkap terpisah, `llms.txt`, yang dirancang khusus supaya
LLM memahami ringkasan dan daftar halaman penting tanpa merender HTML
penuh, lihat [cara membuat llms.txt di Next.js App Router](/blog/cara-membuat-llms-txt-nextjs)
untuk implementasinya.

## Bagaimana Cara Memvalidasi Sitemap dan Robots.txt Setelah Deploy?

Setelah build dan deploy (lihat [cara deploy Next.js ke VPS tanpa Vercel](/blog/cara-deploy-nextjs-ke-vps-tanpa-vercel)
kalau situs masih dijalankan di mesin lokal), akses langsung `/sitemap.xml`
dan `/robots.txt` di browser untuk memastikan isinya benar (URL lengkap
dengan domain, bukan path relatif yang salah). Menurut [dokumentasi resmi Next.js untuk metadata file convention](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap),
`sitemap.ts` di-cache secara default kecuali memakai API dinamis
(request-time), jadi perubahan konten baru biasanya baru muncul setelah
build ulang, bukan seketika.

> "sitemap.js is a special Route Handler that is cached by default unless
> it uses a Request-time API or dynamic config option." ([Next.js
> documentation, file convention `sitemap`](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap)).

Submit `sitemap.xml` ke Google Search Console
(menu Sitemaps) untuk memastikan Google benar-benar memproses daftar
URL-nya, bukan cuma mengandalkan file yang bisa diakses publik.

## Ringkasan: sitemap.ts dan robots.ts sebagai Inti Sitemap-Robots Dinamis

- `app/sitemap.ts` dan `app/robots.ts` adalah file convention Next.js App Router yang menghasilkan `/sitemap.xml` dan `/robots.txt` secara dinamis dari data nyata, tanpa perlu file statis yang diedit manual.
- Untuk sitemap, map data konten yang sudah ada (artikel, produk) jadi entri sitemap dengan `lastModified` jujur dari tanggal konten berubah, bukan tanggal build.
- Untuk robots.txt, `rules` menerima banyak blok per user agent, sehingga crawler AI tertentu bisa diizinkan eksplisit terpisah dari aturan umum.
- Selalu validasi hasilnya lewat akses langsung ke `/sitemap.xml`/`/robots.txt` setelah deploy, dan submit sitemap ke Google Search Console (lihat panduan [cara pakai Google Search Console untuk pemula](/blog/cara-pakai-google-search-console-untuk-pemula)) alih-alih berasumsi Google otomatis menemukannya.
- Butuh bantuan audit atau implementasi SEO teknis seperti ini di situs sendiri? Lihat [layanan SEO teknis dan web development](/layanan) yang ditawarkan.