# Server-Sent Events di Next.js: Lebih Sederhana dari WebSocket

> Sebagian besar fitur real-time hanya mengirim data satu arah. Ini kapan Server-Sent Events mengalahkan WebSocket di Next.js, dan cara mengalirkannya dari route handler.

URL: https://www.matthewswong.com/id/blog/server-sent-events-nextjs-streaming/

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

Setiap permintaan fitur real-time seolah datang dengan asumsi yang sama: kita akan butuh WebSocket. Notifikasi langsung, progress bar untuk pekerjaan panjang, asisten AI yang mengetik jawabannya kata demi kata — refleksnya adalah meraih socket dua arah, server khusus, dan pustaka koneksi ulang. Padahal sebagian besar fitur ini hanya mengirim data satu arah, dari server ke browser. Untuk tugas itu, Server-Sent Events jauh lebih sederhana, dan di Next.js ia pas ke dalam route handler yang sudah Anda kuasai.

Server-Sent Events, atau SSE, adalah standar browser untuk mengalirkan respons berumur panjang melalui HTTP biasa. Klien membuka koneksi dengan API bawaan EventSource, server menjaga respons tetap terbuka dan menulis frame teks saat ada kejadian, dan browser menyambung ulang sendiri jika koneksi terputus. Tidak ada peningkatan protokol, tidak ada port terpisah, dan tidak ada dependensi tambahan. Artikel ini membahas kapan SSE mengalahkan WebSocket, cara kerja format datanya, cara membangun route handler streaming di Next.js App Router, dan pola penting untuk koneksi ulang serta streaming token LLM.

## Kapan Server-Sent Events mengalahkan WebSocket

WebSocket layak dengan kerumitannya ketika kedua sisi terus berbicara — gim multipemain, editor kolaboratif, obrolan tempat indikator mengetik beterbangan dua arah. SSE adalah alat yang lebih baik begitu lalu lintasnya sebagian besar satu arah, dari server ke klien. Itu mencakup banyak hal yang sebenarnya dibangun oleh tim:

Dasbor dan metrik langsung yang menyegar saat angka baru tiba di server.

Pembaruan progres untuk pekerjaan berjalan lama seperti pembuatan laporan, impor, atau deployment.

Notifikasi, umpan aktivitas, dan perubahan status yang didorong ke pengguna yang sedang login.

Streaming respons AI, tempat model bahasa memancarkan token dan UI menampilkannya saat tiba.

Dalam semua kasus ini browser jarang perlu membalas apa pun di tengah aliran; sebuah POST biasa atau permintaan baru sudah cukup untuk perintah sesekali. Memilih SSE di sini menghapus satu kelas infrastruktur penuh — Anda tetap memakai HTTP biasa, cookie autentikasi yang sudah ada, dan load balancer yang sudah ada, serta melewati pusing soal sticky-session dan header upgrade yang dibawa WebSocket.

## Cara kerja format event stream

SSE nyaris memalukan karena sederhananya di level data. Server merespons dengan tipe konten text/event-stream lalu menulis teks UTF-8 dalam frame kecil yang dipisahkan baris kosong. Setiap frame tersusun dari beberapa field opsional, satu per baris:

data — muatannya. Beberapa baris data dalam satu frame digabung dengan baris baru, yang berguna untuk pesan banyak baris.

event — nama opsional agar klien dapat mendengarkan tipe event tertentu alih-alih event message generik.

id — pengenal yang diingat browser. Saat menyambung ulang ia mengirim nilai itu kembali dalam header Last-Event-ID sehingga server dapat melanjutkan dari titik terakhir.

retry — bilangan bulat dalam milidetik yang memberi tahu browser berapa lama menunggu sebelum menyambung ulang setelah terputus.

Baris yang diawali titik dua adalah komentar dan diabaikan; komentar berkala membuat keep-alive murah yang mencegah proksi menganggur menutup koneksi. Karena semuanya hanya teks di atas HTTP, Anda dapat memantau aliran di terminal dengan curl dan membaca persis apa yang dilihat browser.

## Membangun route handler SSE di Next.js

Di App Router, endpoint SSE hanyalah route handler yang mengembalikan Response yang membungkus sebuah ReadableStream. Anda mengantrekan frame teks terenkode saat event terjadi dan menutup controller ketika aliran selesai. Dua baris konfigurasi segmen penting: setel runtime Node.js agar koneksi dapat tetap terbuka, dan paksa rute menjadi dinamis agar Next.js tidak pernah mencoba menyimpannya di cache atau merendernya secara statis.

Header respons melakukan pekerjaan sesungguhnya. Tipe konten text/event-stream memberi tahu browser untuk memperlakukannya sebagai event stream; no-cache dan no-transform mencegah perantara melakukan buffering; dan X-Accel-Buffering yang disetel ke no menonaktifkan buffering respons nginx sehingga frame langsung terkirim alih-alih tiba dalam satu tumpukan di akhir. Membaca sinyal abort dari permintaan memungkinkan Anda mendeteksi ketika klien terputus dan menghentikan pekerjaan mahal — penting, karena jika tidak, tab browser yang tertutup dapat membiarkan sebuah perulangan tetap berjalan di server.

## SSE versus WebSocket secara sekilas

Kedua teknologi ini sebenarnya bukan pesaing, melainkan alat untuk bentuk masalah yang berbeda. Tabel ini menyusun kompromi yang biasanya menentukan pilihan:

Aspek

Server-Sent Events

WebSocket

Arah

Satu arah, server ke klien

Dua arah penuh, kedua sisi

Transport

HTTP biasa, tanpa upgrade

Peningkatan TCP ke protokol ws

Koneksi ulang

Otomatis, bawaan browser

Manual, Anda tulis sendiri

Muatan

Hanya teks UTF-8

Frame teks dan biner

Biaya penyiapan

Sebuah route handler dan EventSource

Server socket dan pustaka klien

Satu catatan historis: di atas HTTP/1.1 browser hanya mengizinkan sekitar enam koneksi bersamaan per domain, dan setiap EventSource yang terbuka masuk hitungan itu di seluruh tab. HTTP/2 memultipleks banyak aliran melalui satu koneksi dan secara efektif menghapus batas itu, jadi menyajikan aplikasi Anda melalui HTTP/2 — yang dilakukan sebagian besar host modern secara bawaan — membuatnya bukan lagi masalah.

## Koneksi ulang dan melanjutkan aliran

Fitur yang membuat SSE terasa tangguh secara gratis adalah koneksi ulang otomatis. Jika koneksi terputus, browser menunggu interval retry lalu membuka permintaan baru sendiri. Jika frame Anda menyertakan field id, browser mengirim nilai terakhir yang dilihatnya dalam header permintaan Last-Event-ID, dan server yang ditulis dengan baik membaca header itu untuk memutar ulang hanya bagian yang terlewat oleh klien. Di sisi klien Anda jarang menyentuh semua ini; Anda memasang listener dan membiarkan EventSource mengelola siklus hidupnya.

Satu hal yang harus Anda tangani secara sengaja adalah menghentikan. EventSource memperlakukan koneksi yang tertutup sebagai sinyal untuk mencoba lagi, jadi jika Anda sekadar mengakhiri respons, browser akan menyambung ulang dalam perulangan. Pancarkan event done eksplisit dan panggil close di klien, atau biarkan aliran terbuka sampai klien berpindah halaman. Memeriksa readyState di penangan error memberi tahu apakah browser sedang mencoba lagi, yang tampak sebagai keadaan CONNECTING, atau benar-benar menyerah, yang tampak sebagai CLOSED.

> Kirim baris komentar seperti satu titik dua setiap 15 sampai 30 detik sebagai detak jantung. Koneksi menganggur sering dimatikan oleh load balancer dan reverse proxy setelah batas waktu tetap, dan komentar berkala kecil menjaga aliran tetap hidup tanpa mengotori data Anda atau memicu event klien apa pun.

## Streaming token LLM melalui SSE

Pola yang membuat SSE populer lagi adalah obrolan AI. Ketika model bahasa menghasilkan balasan, ia memproduksi token satu per satu, dan pengguna berharap melihat jawaban muncul alih-alih menatap pemutar loading. Dokumentasi Next.js menyebut streaming sebagai pendamping umum untuk API LLM, dan SSE adalah transport alaminya: iterasikan potongan teraliran dari model dan antrekan setiap token sebagai frame data. SDK penyedia — Groq, OpenAI, atau Vercel AI SDK — memberi Anda sebuah async iterable, dan Anda meneruskan setiap delta langsung ke dalam ReadableStream.

Di sisi klien listener EventSource yang sama menambahkan setiap token ke pesan yang terlihat, memberi efek mesin ketik yang familiar dengan hampir tanpa kode. Karena ini HTTP biasa, ia bekerja melalui middleware autentikasi dan pembatasan laju yang sudah ada, dan jika pengguna memuat ulang di tengah jawaban browser menyambung ulang otomatis. Khusus untuk obrolan, ingat untuk menutup aliran pada event done agar jawaban yang selesai tidak memicu koneksi ulang tanpa henti.

Buffering adalah alasan nomor satu sebuah aliran SSE tampak menggantung lalu menumpahkan semuanya sekaligus. Kompresi dan buffering proksi adalah pelaku biasa: gzip dan nginx dengan senang menahan frame Anda sampai buffer penuh. Kirim Cache-Control no-transform, setel X-Accel-Buffering ke no untuk nginx, dan hindari membungkus respons dalam middleware kompresi agar setiap frame terkirim persis saat Anda mengantrekannya.

## Jebakan yang perlu diketahui sebelum rilis

SSE itu sederhana, tetapi ada beberapa sudut tajam yang menjebak tim di percobaan pertama. Ingat hal-hal ini:

EventSource hanya mengeluarkan permintaan GET dan tidak dapat mengirim body permintaan atau header khusus. Jika Anda perlu mengirim POST muatan untuk memulai aliran, pakai API fetch dengan pembaca body readable, atau kirim parameter di query string.

Transportnya hanya teks. Enkode data biner sebagai base64 atau kirim string JSON; tidak ada frame biner seperti yang disediakan WebSocket.

Di platform serverless dengan batas eksekusi pendek, aliran berumur panjang bisa terpotong oleh batas waktu fungsi. Utamakan runtime Node.js atau host berjalan lama untuk aliran yang tetap terbuka selama beberapa menit.

Selalu nonaktifkan caching dan buffering. Respons event-stream yang tercache adalah salah satu bug yang paling membingungkan untuk didiagnosis karena endpoint terlihat benar jika berdiri sendiri.

Bersihkan saat terputus. Dengarkan sinyal abort permintaan dan hentikan timer, kursor basis data, atau aliran model agar tab yang tertutup tidak membocorkan sumber daya server.

## Intinya

Sebelum Anda mendirikan server WebSocket, tanyakan ke arah mana data sebenarnya mengalir. Jika jawabannya sebagian besar server ke klien — dasbor, progress bar, notifikasi, jawaban AI teraliran — Server-Sent Events memberi Anda pengalaman langsung yang sama di atas HTTP biasa, dengan koneksi ulang otomatis yang diserahkan browser kepada Anda dan endpoint yang hanyalah satu route handler Next.js lagi. Raih WebSocket ketika Anda benar-benar butuh saluran dua arah; raih SSE, yang merupakan pilihan lebih sederhana jauh lebih sering daripada yang disarankan refleks bawaan, untuk selebihnya.

## Sumber dan bacaan lanjutan

- MDN — Menggunakan server-sent events
- MDN — Referensi antarmuka EventSource
- Dokumentasi Next.js — Route Handlers dan streaming
- Wikipedia — Server-sent events

## Source links

- https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
- https://developer.mozilla.org/en-US/docs/Web/API/EventSource
- https://nextjs.org/docs/app/api-reference/file-conventions/route
- https://en.wikipedia.org/wiki/Server-sent_events

## FAQ

### Apa itu Server-Sent Events dan apa bedanya dengan WebSocket?

Server-Sent Events, atau SSE, adalah standar browser untuk mengalirkan respons berumur panjang dari server ke klien melalui HTTP biasa memakai API EventSource. Berbeda dengan WebSocket, SSE hanya satu arah dan tidak meningkatkan koneksi, sehingga lebih sederhana dijalankan. WebSocket menambah saluran dua arah penuh yang sepadan dengan kerumitannya hanya ketika klien juga perlu mendorong data terus-menerus.

### Bagaimana cara membuat endpoint Server-Sent Events di Next.js?

Tulis route handler di App Router yang mengembalikan Response yang membungkus ReadableStream. Antrekan frame teks UTF-8 memakai TextEncoder dan setel tipe konten ke text/event-stream dengan header no-cache. Gunakan runtime Node.js dan paksa rute menjadi dinamis agar koneksi tetap terbuka dan tidak pernah tercache.

### Kapan saya sebaiknya memilih SSE alih-alih WebSocket?

Pilih SSE ketika data mengalir sebagian besar satu arah, dari server ke klien. Dasbor langsung, progress bar pekerjaan, notifikasi, dan jawaban AI teraliran semuanya cocok dengan bentuk ini. Pilih WebSocket hanya ketika kedua sisi perlu mengirim data terus-menerus, seperti gim multipemain atau editor kolaboratif.

### Apakah SSE menyambung ulang otomatis jika koneksi terputus?

Ya. Browser menunggu interval retry lalu membuka kembali koneksi sendiri tanpa kode klien apa pun. Jika frame Anda menyertakan field id, browser mengirimnya kembali dalam header Last-Event-ID sehingga server dapat melanjutkan dari event terakhir yang diterima klien. Untuk menghentikan koneksi ulang, pancarkan event done dan panggil close pada EventSource.

### Bisakah saya mengalirkan token LLM ke browser dengan SSE?

Bisa, dan ini pemakaian paling populer saat ini. Iterasikan potongan teraliran dari penyedia model seperti Groq atau OpenAI dan antrekan setiap token sebagai frame data dalam ReadableStream. Klien mendengarkan dengan EventSource dan menambahkan token untuk efek mesin ketik. Nonaktifkan buffering proksi dan gzip agar token langsung terkirim alih-alih tiba sekaligus.

---

- HTML version: https://www.matthewswong.com/id/blog/server-sent-events-nextjs-streaming/
- English: https://www.matthewswong.com/en/blog/server-sent-events-nextjs-streaming/
- 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
