# Gambar Open Graph Dinamis dengan Next.js ImageResponse

> Cara membuat gambar Open Graph yang unik untuk setiap artikel blog secara langsung saat permintaan menggunakan Next.js ImageResponse dan Satori, tanpa perlu alat desain tambahan.

URL: https://www.matthewswong.com/id/blog/nextjs-dynamic-og-image-generation/

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

Setiap pratinjau tautan yang pernah kamu lihat di Slack, iMessage, LinkedIn, atau X didukung oleh beberapa meta tag di bagian head halaman, dan yang paling penting di antaranya adalah gambar. Selama bertahun-tahun, cara paling mudah memenuhi tag itu adalah mengekspor satu banner statis dari alat desain lalu memakainya berulang kali. Cara itu cukup baik untuk halaman utama. Namun cara itu langsung bermasalah begitu kamu memiliki lima puluh artikel blog, masing-masing dengan judul, kategori, dan estimasi waktu baca yang berbeda, dan kamu ingin tautan yang dibagikan benar-benar menyampaikan isi artikel sebelum orang mengekliknya.

Next.js menyelesaikan masalah ini lewat konstruktor ImageResponse yang diekspor dari modul next slash og. Konstruktor ini memungkinkan kamu menggambarkan sebuah gambar sebagai JSX dan CSS biasa, model berpikir yang sama seperti saat membangun komponen, lalu mendapatkan hasil PNG yang dirender secara langsung. Gabungkan dengan konvensi berkas opengraph-image dan kamu mendapatkan gambar berbagi yang unik dan sesuai identitas brand untuk setiap rute, dihasilkan dari data nyata, hampir tanpa infrastruktur tambahan. Artikel ini membahas mekanismenya, jebakan seputar font dan caching yang sering membuat orang keliru, serta cara memverifikasi hasilnya sebelum dirilis.

## Konvensi berkas: opengraph-image.tsx

Next.js memperlakukan berkas bernama opengraph-image di dalam segmen rute mana pun sebagai route handler khusus. Alih-alih mengekspor fungsi GET, kamu mengekspor fungsi async default yang mengembalikan ImageResponse, sebuah Blob, atau Response biasa. Next.js otomatis menyusun meta tag og colon image yang dihasilkan, termasuk lebar, tinggi, dan tipe konten, sehingga kamu tidak perlu menulis tag tersebut secara manual. Contoh di bawah membaca parameter slug dinamis, mencari artikel yang sesuai, lalu merender judul dan kategorinya langsung ke dalam gambar yang dihasilkan.

## Bagaimana ImageResponse sebenarnya merender piksel

Di balik layar, ImageResponse menggabungkan tiga proyek sumber terbuka yang berbeda: Satori mengubah JSX dan CSS kamu menjadi SVG, lalu renderer berbasis Rust bernama resvg merasterisasi SVG itu menjadi PNG, dan seluruh alur ini dikemas sebagai pustaka at vercel slash og yang diekspor ulang oleh Next.js. Karena Satori harus mengimplementasikan tata letak CSS sendiri alih-alih mendelegasikannya ke mesin browser sungguhan, hanya sebagian kecil properti CSS yang didukung.

- Tata letak hanya mendukung flexbox. Tidak ada dukungan grid, jadi susun komposisi dengan div bersarang, flex direction, dan gap seperti pada templat email lama.
- Pembungkusan teks, posisi absolut, dan gradasi latar belakang semuanya berfungsi, sehingga mencakup sebagian besar desain kartu OG di dunia nyata.
- Gambar dapat disematkan sebagai data URI atau sebagai array buffer mentah yang dikirim ke atribut src, berguna untuk logo atau avatar penulis yang sudah disiapkan sejak waktu build.
- Seluruh bundel, yaitu JSX, font, dan gambar yang disematkan secara gabungan, dibatasi maksimal 500 kilobita, jadi jaga agar subset font dan aset logo tetap ringkas.

> Rancang tata letakmu dulu di Vercel OG Playground sebelum menghubungkannya ke aplikasi. Playground ini menjalankan mesin Satori yang sama persis di browser, sehingga apa yang kamu lihat di sana adalah apa yang akan kamu dapatkan dari route handler, dan bereksperimen di sana jauh lebih cepat daripada mendeploy ulang hanya untuk memeriksa selisih satu piksel.

## Font kustom: bagian yang paling sering salah pertama kali

ImageResponse sudah dilengkapi font sans serif bawaan, tetapi ia tidak akan mengenal font tampilan yang benar-benar dipakai brand kamu kecuali kamu memuatnya sendiri. Hanya format ttf, otf, dan woff yang didukung, dan dokumentasi resmi secara khusus menyarankan ttf atau otf dibanding woff karena keduanya diparsing lebih cepat di dalam alur rendering. Detail krusialnya adalah di mana kamu memuat berkas font tersebut. Jika kamu memanggil pembacaan filesystem atau fetch di dalam fungsi komponen itu sendiri, kamu membaca ulang byte yang sama pada setiap permintaan. Muat sekali saja di lingkup modul, sehingga byte tersebut tersimpan di memori selama masa hidup instance server dan dipakai ulang pada pemanggilan yang sudah hangat.

> Jika rute opengraph-image kamu berjalan di Edge runtime, node colon fs tidak tersedia, sehingga kamu tidak bisa membaca berkas font langsung dari disk. Sebagai gantinya, ambil font lewat HTTP dari CDN atau URL folder public milikmu sendiri, dan cache respons itu dengan cara yang sama seperti pada Node runtime, karena jika tidak, setiap cold start akan membayar ulang biaya unduhan penuh.

## Generasi statis versus generasi saat permintaan

Sebuah opengraph-image yang dihasilkan bersifat statically optimized dan secara default hanya diproduksi sekali saat waktu build, sama seperti halaman yang tidak memiliki dependensi data dinamis. Ia baru beralih otomatis ke generasi saat permintaan ketika menyentuh API waktu permintaan, misalnya membaca cookie atau header, atau ketika mengambil data yang tidak dicache. Perbedaan ini sangat berpengaruh pada biaya dan latensi: gambar statis dibuat sekali dan disajikan dari cache selamanya, sementara gambar saat permintaan dirender ulang setiap kali crawler media sosial mengaksesnya kecuali kamu menambahkan lapisan caching sendiri di atasnya.

| Mode generasi | Kapan terjadi | Paling cocok untuk |
| --- | --- | --- |
| Statis (waktu build) | Tidak ada cookie, header, atau panggilan fetch tanpa cache di dalam fungsi | Halaman tetap seperti halaman utama atau halaman tentang |
| Saat permintaan, dicache | Mengambil data dengan perilaku cache fetch bawaan | Artikel blog dan halaman produk dengan parameter slug |
| Saat permintaan, tanpa cache | Membaca cookie, header, atau secara eksplisit menonaktifkan cache fetch | Kartu personal, misalnya gambar referral dengan nama pengguna |

## Strategi caching yang praktis

Untuk sebuah blog, titik idealnya hampir selalu berada di baris tengah tabel tersebut: biarkan pengambilan data di dalam opengraph-image memakai perilaku cache bawaan framework sehingga PNG yang dirender pada dasarnya dihasilkan sekali per artikel lalu dipakai ulang, sambil tetap memungkinkan rebuild penuh untuk memperbaruinya setiap kali konten berubah. Tiga kebiasaan berikut membuat pendekatan ini tetap dapat diandalkan di produksi.

- Tetapkan ekspor alt, size, dan content type secara eksplisit pada setiap berkas opengraph-image. Ketiganya otomatis menjadi teks alt yang dapat diakses serta meta tag lebar dan tinggi, sehingga crawler tidak perlu menebak rasio aspeknya.
- Jaga JSX tetap sederhana agar rendernya jauh di bawah satu detik. Generasi gambar yang lambat tidak terlihat oleh pengunjung biasa, tetapi sangat terlihat oleh crawler media sosial, yang beberapa di antaranya menerapkan timeout singkat sebelum akhirnya menampilkan tanpa gambar sama sekali.
- Jika kamu memakai generateImageMetadata untuk menghasilkan beberapa variasi, misalnya gambar persegi untuk satu platform dan gambar lebar untuk platform lain, beri masing-masing id eksplisit agar cache key tetap stabil di setiap deploy.

> Karena gambar tersebut diturunkan langsung dari metadata judul, kategori, dan waktu baca yang sama dengan yang sudah dirender halamanmu, gambar itu tidak akan pernah tidak sinkron dengan artikel sebenarnya seperti yang biasa terjadi pada banner buatan tangan setelah revisi konten yang kesepuluh.

## Memverifikasi hasil sebelum dirilis

Gambar yang dihasilkan hanyalah respons dari sebuah rute, sehingga pemeriksaan paling cepat adalah permintaan HTTP biasa ke URL opengraph-image untuk artikel tertentu, memastikan responsnya berstatus 200 dan bertipe konten gambar. Namun itu hanya membuktikan piksel-pikselnya ada, bukan bahwa tag di head halaman sudah benar atau bahwa platform-platform besar akan menampilkannya dengan baik. Setiap platform besar mencache versi pertama sebuah tautan secara agresif, sehingga setelah memperbaiki sesuatu kamu perlu memaksa pemindaian ulang menggunakan alat debugging milik platform tersebut, bukan sekadar me-refresh halaman di browser.

## Sumber

- Dokumentasi Next.js — Referensi API ImageResponse
- Dokumentasi Next.js — Konvensi berkas opengraph-image dan twitter-image
- Wikipedia — Protokol Open Graph

> **Key takeaway:** Next.js dapat menghasilkan gambar Open Graph yang unik untuk setiap artikel blog secara langsung saat diakses, menggunakan konstruktor ImageResponse yang mengubah JSX dan CSS menjadi PNG lewat Satori dan resvg. Memuat font kustom sekali di lingkup modul, memilih strategi caching yang tepat, dan memverifikasi hasilnya dengan alat debugging platform adalah kunci agar pendekatan ini andal di produksi.

Konstruktor yang diekspor dari next/og yang merender JSX dan CSS menjadi gambar PNG, dipakai untuk membangun gambar Open Graph dan Twitter card tanpa alat desain khusus.

Pustaka sumber terbuka yang mengubah JSX dan CSS menjadi SVG menggunakan mesin tata letaknya sendiri, karena tidak bisa mendelegasikan proses render ke browser sungguhan.

Pustaka rendering SVG berbasis Rust yang merasterisasi SVG hasil Satori menjadi gambar PNG akhir.

Runtime JavaScript ringan yang dapat dijalankan Next.js di edge jaringan, yang tidak memiliki API Node.js seperti modul filesystem, sehingga aset harus diambil lewat HTTP alih-alih dibaca langsung dari disk.

Fungsi Next.js yang memungkinkan satu rute menghasilkan beberapa varian gambar, misalnya ukuran berbeda untuk platform berbeda, masing-masing diberi id eksplisit agar cache key tetap stabil.

## Source links

- https://nextjs.org/docs/app/api-reference/functions/image-response
- https://nextjs.org/docs/app/api-reference/file-conventions/metadata/opengraph-image
- https://en.wikipedia.org/wiki/Open_Graph_protocol

## FAQ

### Untuk apa Next.js ImageResponse digunakan?

ImageResponse adalah konstruktor yang diekspor dari next slash og yang mengubah JSX dan CSS menjadi PNG yang dirender saat permintaan atau saat waktu build. Konstruktor ini paling umum dipakai untuk menghasilkan gambar Open Graph dan Twitter card sehingga setiap halaman atau artikel blog mendapatkan gambar berbagi sosial yang unik dan sesuai identitas brand, bukan satu banner statis yang dipakai berulang kali.

### Mengapa font kustom saya tidak muncul di gambar OG yang dihasilkan?

ImageResponse hanya mendukung format font ttf, otf, dan woff, dan ia tidak akan otomatis mengenali font hanya karena font itu dimuat di bagian lain aplikasimu. Kamu harus membaca sendiri berkas font tersebut lalu mengirimkannya ke opsi fonts sebagai data biner mentah. Kesalahan umum adalah memuat font di dalam fungsi komponen pada setiap permintaan, bukan sekali saja di lingkup modul, yang tetap berfungsi tetapi membuang waktu pada setiap pemanggilan.

### Bagaimana cara membuat gambar OG yang berbeda untuk setiap artikel blog?

Buat berkas opengraph-image.tsx di dalam segmen rute dinamis, misalnya di dalam folder slug, lalu baca slug dari argumen params yang diterima fungsi tersebut. Gunakan slug itu untuk mencari judul dan kategori artikel, kemudian render keduanya ke dalam JSX ImageResponse. Next.js otomatis menyusun meta tag yang tepat di head halaman, sehingga kamu tidak perlu menambahkan apa pun secara manual.

### Bisakah saya memakai filesystem Node.js di dalam rute gambar OG?

Hanya jika rute tersebut berjalan di runtime Node.js, yang memang menjadi default. Jika kamu mengubah rute ke Edge runtime, node colon fs tidak tersedia dan setiap pembacaan filesystem akan gagal. Dalam kasus itu, ambil font dan aset lain lewat HTTP dari URL public, lalu cache byte yang diambil agar tidak diunduh ulang pada setiap permintaan.

### Mengapa gambar OG baru saya tidak muncul saat tautan dibagikan?

Sebagian besar platform media sosial mencache versi pertama pratinjau tautan secara agresif dan akan tetap menampilkan gambar lama meskipun kamu sudah memperbaiki route handler. Pastikan dulu rute itu sendiri mengembalikan gambar terbaru lewat permintaan HTTP langsung, lalu gunakan alat debugging milik platform tersebut, seperti Sharing Debugger dari Facebook atau Post Inspector dari LinkedIn, untuk memaksa pemindaian ulang, bukan sekadar me-refresh halaman biasa.

---

- HTML version: https://www.matthewswong.com/id/blog/nextjs-dynamic-og-image-generation/
- English: https://www.matthewswong.com/en/blog/nextjs-dynamic-og-image-generation/
- 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
