Belajar Fullstack Developer - Real-Time Features
Episode 14 of 28

Belajar Fullstack Developer - Real-Time Features

Membangun fitur real-time dengan WebSocket dan SSE: memahami kapan memakai masing-masing, mengimplementasikan Server-Sent Events di Next.js, dan menghubungkan WebSocket untuk kolaborasi dua arah.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Tidak semua data harus dimuat ulang dengan refresh. Chat, notifikasi, status transaksi, dan daftar tugas yang berubah bersamaan antar pengguna menuntut real-time: server mendorong data ke browser begitu tersedia. Episode ini membahas dua teknologi utamanya — WebSocket dan SSE (Server-Sent Events) — dan kapan memakai masing-masing.

Real-time adalah masalah fullstack sejati: melibatkan transport di jaringan, state di server, dan sinkronisasi di client. Jika kalian sudah memahami episode 8 (state & data fetching), episode ini tinggal mengganti sumber data statis menjadi aliran (stream) hidup.

WebSocket vs SSE: Bukan Saingan, tapi Alat Berbeda

Kedua teknologi sama-sama membuat koneksi persisten dari browser ke server. Bedanya di arah aliran data:

AspekWebSocketSSE (Server-Sent Events)
ArahDua arah (client ↔ server)Satu arah (server → client)
Protokolws:// (di atas TCP)HTTP biasa, streaming
ReconnectManual, di tangan kalianOtomatis bawaan browser
Balik proxy/LBButuh konfigurasi khususIkut HTTP biasa (mudah)
Cocok untukChat, game, kolaborasiNotifikasi, feed, progres

Tip

Aturan praktis 2026: gunakan SSE jika server cukup mendorong data (notifikasi, progres, feed) — ia jauh lebih sederhana, reconnect otomatis, dan berjalan mulus di balik proxy. Simpan WebSocket untuk kebutuhan dua arah yang intens: chat, kolaborasi kursor, game real-time. Memilih SSE saat cukup bisa menghemat banyak biaya operasional.

SSE: Notifikasi Real-Time dengan Next.js

SSE di Next.js adalah route handler yang mengembalikan streaming response. Contoh nyata: notifikasi "catatan baru dibuat" untuk semua pengguna.

src/app/api/events/route.ts
export async function GET() {
  const stream = new ReadableStream({
    start(controller) {
      const send = (data: unknown) => {
        controller.enqueue(`data: ${JSON.stringify(data)}\n\n`)
      }
      clients.add(send)
      controller.enqueue(`data: ${JSON.stringify({ type: "connected" })}\n\n`)
    },
    cancel() {
      clients.delete(send)
    },
  })
  return new Response(stream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache, no-transform",
      Connection: "keep-alive",
    },
  })
}

Format SSE sangat sederhana: tiap pesan diawali data: dan diakhiri dua baris baru. Saat ada catatan baru, broadcast ke semua client:

Broadcast saat data berubah
// di dalam server action / setelah query
for (const send of clients) {
  send({ type: "note.created", noteId, title })
}

Di client, browser menangani koneksi dan reconnect otomatis — hanya butuh EventSource:

src/hooks/use-events.ts
"use client"
 
import { useEffect } from "react"
 
export function useEvents(onEvent: (data: any) => void) {
  useEffect(() => {
    const source = new EventSource("/api/events")
    source.onmessage = (e) => onEvent(JSON.parse(e.data))
    return () => source.close()
  }, [onEvent])
}

Satu koneksi SSE memberi semua notifikasi tanpa polling. Perhatikan: clients adalah set di dalam memori proses server — cocok untuk satu instance; untuk multi-instance kita butuh pub/sub Redis (dibahas di episode 22).

WebSocket: Komunikasi Dua Arah

Ketika butuh pengguna mengirim dan menerima secara real-time (chat, kolaborasi), WebSocket adalah jawabannya. Next.js mendukung WebSocket via route handler dengan adapter khusus; untuk aplikasi terpisah, Socket.IO tetap menjadi pilihan paling praktis karena menangani reconnect, fallback, dan room:

Server Socket.IO
import { Server } from "socket.io"
 
export function setupSocket(httpServer) {
  const io = new Server(httpServer, {
    cors: { origin: process.env.APP_URL },
  })
 
  io.on("connection", (socket) => {
    socket.on("chat:send", ({ room, message }) => {
      io.to(room).emit("chat:receive", { message })
    })
    socket.join(`user:${socket.handshake.auth.userId}`)
  })
}

Client-nya simetris — membuka koneksi, mendengarkan event, dan mengirim event:

Client Socket.IO
"use client"
 
import { io } from "socket.io-client"
 
export function useChat(room: string) {
  const socket = io(process.env.NEXT_PUBLIC_SOCKET_URL, {
    auth: { token: "session-token" },
  })
 
  return {
    send: (message: string) => socket.emit("chat:send", { room, message }),
    onReceive: (cb: (m: string) => void) =>
      socket.on("chat:receive", ({ message }) => cb(message)),
  }
}

Autentikasi WebSocket wajib diperhatikan: token diverifikasi saat handshake (di auth), dan setiap event yang sensitif tetap diverifikasi di server — bukan hanya sekali di koneksi.

Live Updates Tanpa Menulis Transport

Jika kalian tidak ingin kelola koneksi sama sekali, Next.js 2026 punya jalan pintas: Server Actions + revalidation + optimistic updates (episode 7-8) untuk data satu pengguna, dan polling revalidate (episode 8) untuk data yang berubah tiap menit. Real-time sungguhan baru wajib ketika perubahan harus terlihat dalam detik oleh pengguna lain.

100%

Praktik: Fitur Realtime

Selesaikan dengan urutan berikut:

  1. Buat src/app/api/events/route.ts (SSE) dan useEvents hook.
  2. Di server action createNote, broadcast note.created ke semua client.
  3. Di halaman /notes, tampilkan notifikasi toast saat event note.created masuk — tanpa refresh.
  4. (Opsional lanjutan) Tambahkan chat sederhana dua pengguna dengan Socket.IO.
Uji SSE dari terminal
curl -N http://localhost:3000/api/events

Terminal harus menampilkan data: {"type":"connected"} dan tetap terbuka — bukti aliran berjalan.

Penutup

Inti yang harus dibawa pulang:

  • WebSocket untuk dua arah intens; SSE untuk dorongan server → client; polling untuk sisanya.
  • SSE = route handler streaming, reconnect otomatis, mudah di balik proxy.
  • WebSocket = chat/kolaborasi, kelola reconnect & auth di handshake.
  • Broadcast antar instance butuh pub/sub Redis (episode 22).
  • Jangan real-time bila revalidate/polling sudah cukup — hemat operasional.

Di episode 15 selanjutnya kita membahas caching & performance — Redis, CDN, ISR, dan Core Web Vitals — untuk mengoptimalkan aplikasi dari ujung ke ujung. Sampai jumpa di episode 15!

Belajar Fullstack Developer - Real-Time Features | Belajar Fullstack