# Arsitektur Hybrid Rendering Next.js: SSR, ISR, dan Edge Caching di Cloudflare

> Diterbitkan oleh Literally Web ID pada 21 Oct 2026
> Sumber: https://literally.web.id/articles/arsitektur-hybrid-rendering-nextjs-ssr-isr-dan-edge-caching-di-cloudflare

---

# Arsitektur Hybrid Rendering Next.js: SSR, ISR, dan Edge Caching di Cloudflare

## 1. Titik Awal Masalah: Skenario Nyata di Produksi

Pagi itu, pukul 08.15 WIB, Slack berdering tanpa henti. Tim marketing baru saja meluncurkan kampanye flash sale untuk platform e-commerce yang kami kelola. Dalam waktu kurang dari tiga menit, metrik di dashboard Grafana melonjak drastis. Permintaan HTTP menembus angka 45.000 request per detik (RPS). CPU pada cluster Node.js kami yang menjalankan Server-Side Rendering (SSR) murni langsung terpaku di angka 99%. Tak lama kemudian, database MySQL utama kami mengalami *connection exhaustion*, dan ribuan pengguna mulai disambut oleh layar putih dengan pesan klise: *504 Gateway Time-out*.

Kejadian seperti ini adalah mimpi buruk bagi siapa pun yang memegang tanggung jawab atas infrastruktur web skala besar. Masalah utamanya klise namun mematikan: setiap klik pengguna memicu eksekusi kode server, merender komponen React dari nol, dan memukul database secara langsung untuk mengambil data produk yang sebenarnya tidak berubah secara real-time. Nginx di depan kewalahan, PHP-FPM atau Node.js prosesnya macet, dan arsitektur kita runtuh bukan karena kurang cerdas, melainkan karena kita salah memilih strategi rendering untuk tipe beban kerja tersebut.

Pengalaman pahit ini memaksa kami merombak total pendekatan arsitektur web modern. Kita tidak bisa lagi hanya mengandalkan SSR mentah atau terjebak dalam statisme murni dari Static Site Generation (SSG) yang membuat build time memakan waktu berjam-jam setiap kali ada pembaruan produk. Jawabannya ada pada pendekatan hibrida: memadukan keleluasaan SSR, kecepatan caching inkremental (ISR), dan mendistribusikan beban tersebut langsung ke edge network Cloudflare. Dan untuk memahami bagaimana racikan ini bisa menyelamatkan infrastruktur Anda dari bencana serupa, mari kita bedah cara kerjanya di balik layar.

## 2. Di Balik Layar: Bagaimana Sistem Ini Bekerja Tanpa Sihir

Banyak junior engineer menganggap Edge Caching dan SSR adalah dua kutub yang saling bertolak belakang. "Kalau pakai SSR, berarti dinamis dan tidak bisa di-cache di CDN," begitu argumen yang sering saya dengar. Padahal, jika kita melihat arsitektur modern berbasis Cloudflare Workers dan Next.js, batas antara server asal (*origin server*) dan edge menjadi sangat tipis dan cair.

Mari kita bayangkan sebuah peta global. Ketika seorang pengguna di Jakarta mengakses halaman detail produk, permintaan tersebut tidak langsung menghantam server Node.js Anda yang berlokasi di data center AWS Singapura. Permintaan itu dicegat oleh point of presence (PoP) Cloudflare terdekat di Jakarta. Di sinilah keajaiban terjadi. Melalui konfigurasi Cache-Control dan Edge Worker yang tepat, Cloudflare akan memeriksa: apakah kita memiliki salinan halaman ini yang masih segar?

> [!IMPORTANT]
> Jangan pernah menyamakan caching tradisional Nginx dengan Edge Caching di Cloudflare. Di edge, kita tidak hanya menyimpan file HTML statis, tetapi kita juga bisa memprogram logika penanganan *stale-while-revalidate* langsung di level worker, memvalidasi token otorisasi secara instan tanpa menyentuh origin, dan mengeksekusi sebagian kecil logika Next.js sebelum request diteruskan.

Jika data sudah ada di cache edge, respons dikembalikan dalam kurun waktu kurang dari 15 milidetik tanpa beban sepeser pun pada cluster backend atau database. Namun, jika cache kedaluwarsa atau terjadi *cache miss*, Cloudflare akan meneruskan permintaan ke origin, merender halaman secara parsial, lalu memperbarui cache edge secara asinkron. Alur ini mengubah paradigma lama kita dari "setiap request adalah beban" menjadi "request pertama adalah beban, sisanya adalah kecepatan murni". Dan untuk menentukan kapan sebuah halaman harus dirender ulang atau disajikan dari cache, kita harus menyelami pilihan pendekatan teknis berikutnya.

## 3. Pilihan Pendekatan & Kompromi yang Harus Diambil

Dalam merancang arsitektur hybrid, kita dihadapkan pada tiga pilar utama: Server-Side Rendering (SSR), Incremental Static Regeneration (ISR), dan Static Site Generation (SSG). Masing-masing memiliki konsekuensi biaya, performa, dan kompleksitas operasional yang berbeda. Mari kita bandingkan secara objektif melalui tabel keputusan di bawah ini:

| Fitur / Parameter | Server-Side Rendering (SSR) | Incremental Static Regeneration (ISR) | Edge Caching + SSR Hybrid |
|-------------------|-----------------------------|----------------------------------------|---------------------------|
| **Kecepatan Respons (TTFB)** | Lambat (tergantung beban backend & DB) | Sangat Cepat (disajikan dari CDN/Edge) | Sangat Cepat (Edge-cached HTML) |
| **Beban Database** | Tinggi (setiap request memukul DB) | Rendah (hanya saat background regen) | Sangat Rendah (tergantung durasi cache) |
| **Kesesuaian Data** | Real-time penuh | Mendekati real-time (eventual consistency)| Dapat diatur fleksibel per rute |
| **Kompleksitas Infrastruktur** | Sedang (butuh autoscaling cluster Node)| Tinggi (butuh penanganan distributed cache)| Sangat Tinggi (kombinasi Worker & Next.js)|

> [!TIP]
> Jangan mencoba menggunakan satu pendekatan untuk seluruh halaman situs Anda. Halaman keranjang belanja (*cart*) atau profil pengguna wajib menggunakan SSR murni atau Client-Side Rendering (CSR) karena sifatnya yang sangat personal. Sebaliknya, halaman katalog produk, artikel blog, dan landing page hukum wajib menggunakan kombinasi ISR dan Edge Caching.

Kompromi terbesar dalam memilih pendekatan hibrida ini adalah masalah *cache invalidation*. Ketika data harga produk berubah di database, bagaimana cara kita memastikan edge Cloudflare segera menghapus cache lama tanpa harus menunggu masa TTL (Time-to-Live) habis? Jawabannya menuntut kita untuk membangun fondasi lingkungan yang tepat terlebih dahulu sebelum menulis baris kode pertama.

## 4. Meracik Lingkungan: Persiapan & Prasyarat Lapangan

Sebelum kita menyentuh kode Next.js, pastikan fondasi infrastruktur pendukung Anda sudah siap. Arsitektur hybrid yang tangguh membutuhkan keselarasan antara versi Node.js, konfigurasi Cloudflare Zone, serta pengelolaan environment variables yang ketat. 

Pertama, pastikan Anda menggunakan runtime Node.js minimal versi 20.x LTS untuk mendukung fitur-fitur modern seperti `fetch` native dan pengelolaan memori yang lebih optimal di serverless environment. Berikut adalah struktur dasar proyek yang kami gunakan di lingkungan production:

```text
my-hybrid-app/
├── .env.production
├── wrangler.toml
├── next.config.mjs
├── src/
│   ├── app/
│   │   ├── api/
│   │   │   └── revalidate/
│   │   │       └── route.js
│   │   └── products/
│   │       └── [slug]/
│   │           └── page.jsx
│   └── lib/
│       └── db.js
└── package.json
```

Konfigurasi `wrangler.toml` untuk deployment ke Cloudflare Workers harus disiapkan secara presisi. File ini bertindak sebagai jembatan antara aplikasi Next.js Anda dan infrastruktur edge Cloudflare:

```toml
name = "next-hybrid-production"
main = ".open-next/worker.js"
compatibility_date = "2024-03-01"

[vars]
ENVIRONMENT = "production"
DATABASE_POOL_MAX = 5

[site]
bucket = ".open-next/assets"
```

> [!WARNING]
> Jangan pernah mengabaikan parameter `compatibility_date` di `wrangler.toml`. Cloudflare terus memperbarui runtime API mereka; mengunci tanggal kompatibilitas mencegah aplikasi Anda mendadak rusak akibat perubahan perilaku *runtime* global.

Setelah fondasi lingkungan dan konfigurasi dasar siap, langkah berikutnya adalah merangkai kode implementasi nyata yang menyatukan logika Next.js dengan mekanisme cache di edge.

## 5. Langkah Implementasi: Membangun Solusi yang Tangguh

Untuk mengimplementasikan arsitektur hybrid ini, kita akan memanfaatkan fitur App Router di Next.js bersama dengan strategi revalidasi inkremental. Kita juga akan menulis sebuah API route khusus di server untuk memicu pembersihan cache secara terprogram (*purge cache*) ketika ada pembaruan data dari panel admin.

Berikut adalah implementasi halaman produk dinamis (`src/app/products/[slug]/page.jsx`) yang memanfaatkan opsi `revalidate` untuk ISR:

```javascript
import { notFound } from 'next/navigation';
import { queryDatabase } from '@/lib/db';

// Menetapkan revalidate setiap 60 detik (ISR)
export const revalidate = 60;

// Opsional: Generate static params untuk produk terpopuler saat build time
export async function generateStaticParams() {
  const products = await queryDatabase('SELECT slug FROM products LIMIT 100');
  return products.map((product) => ({
    slug: product.slug,
  }));
}

async function getProductData(slug) {
  const data = await queryDatabase('SELECT * FROM products WHERE slug = ?', [slug]);
  if (!data.length) return null;
  return data[0];
}

export default async function ProductPage({ params }) {
  const { slug } = params;
  const product = await getProductData(slug);

  if (!product) {
    notFound();
  }

  return (
    <main className="container mx-auto px-4 py-8">
      <h1 className="text-3xl font-bold">{product.name}</h1>
      <p className="text-xl text-green-600 mt-2">Rp {product.price.toLocaleString('id-ID')}</p>
      <div className="mt-4 text-gray-700 leading-relaxed">
        {product.description}
      </div>
    </main>
  );
}
```

Namun, bagaimana jika admin mengubah harga produk dan ingin perubahan tersebut langsung tampil detik itu juga tanpa menunggu waktu revalidate 60 detik habis? Di sinilah kita membutuhkan endpoint *On-Demand Revalidation* yang dikombinasikan dengan Cloudflare API untuk melakukan *Cache Purge* secara instan. Mari kita bedah baris kode krusial tersebut pada bagian selanjutnya.

## 6. Membedah Baris Kode Krusial yang Kerap Menjebak

Bagian paling rawan dalam arsitektur hybrid rendering adalah sinkronisasi antara aksi pembaruan data di database dan pembersihan cache di CDN. Jika salah konfigurasi, pengguna akan melihat data lama yang basi, atau sebaliknya, server Anda akan kebanjiran beban karena cache terlalu sering dihapus secara manual (*cache stampede*).

Berikut adalah kode API Route untuk menangani *On-Demand Revalidation* di Next.js yang dipicu oleh webhook backend atau CMS Anda (`src/app/api/revalidate/route.js`):

```javascript
import { revalidatePath } from 'next/cache';
import { NextResponse } from 'next/server';

export async function POST(request) {
  try {
    const body = await request.json();
    const { secret, slug } = body;

    // Validasi token rahasia untuk keamanan endpoint
    if (secret !== process.env.REVALIDATION_SECRET) {
      return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
    }

    if (!slug) {
      return NextResponse.json({ message: 'Slug is required' }, { status: 400 });
    }

    // Panggil fungsi revalidate path di Next.js
    revalidatePath(`/products/${slug}`);

    // Lakukan pembersihan cache secara langsung di Cloudflare Edge via API (Opsional tapi direkomendasikan)
    await purgeCloudflareCache([`/products/${slug}`]);

    return NextResponse.json({ revalidated: true, now: Date.now() });
  } catch (err) {
    return NextResponse.json({ message: 'Error revalidating', error: err.message }, { status: 500 });
  }
}

async function purgeCloudflareCache(paths) {
  const zoneId = process.env.CLOUDFLARE_ZONE_ID;
  const apiToken = process.env.CLOUDFLARE_API_TOKEN;
  
  const urls = paths.map(path => `https://example.com${path}`);

  const response = await fetch(`https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ files: urls }),
  });

  if (!response.ok) {
    throw new Error('Gagal membersihkan cache di Cloudflare Edge');
  }
}
```

> [!WARNING]
> Perhatikan variabel `REVALIDATION_SECRET`. Jangan pernah mengekspos token ini di sisi client (browser). Kegagalan mengamankan endpoint ini bisa memicu serangan *Denial of Service* (DoS) di mana pihak luar dapat memicu revalidasi terus-menerus dan menghancurkan performa database Anda.

Kode di atas menangani logika revalidasi dengan aman. Namun, seberapa tangguh sistem ini ketika dihadapkan pada skenario traffic nyata di lapangan? Mari kita uji ketahanannya.

## 7. Bertahan di Bawah Tekanan: Skenario Traffic Nyata

Bayangkan skenario terburuk: lonjakan traffic mendadak sebanyak 100.000 pengguna bersamaan mengakses halaman promo yang baru saja dibersihkan cachenya (*cache purge*). Tanpa strategi perlindungan yang tepat, fenomena yang disebut *Cache Stampede* akan terjadi. Ribuan request akan secara bersamaan menembus edge, gagal menemukan cache, lalu menghantam database backend Anda secara serentak.

Untuk meredam hantaman ini, kita menerapkan pola **Stale-While-Revalidate** di tingkat Cloudflare Cache Rules dan mengoptimalkan manajemen koneksi database. Ketika cache sedang diregenerasi di latar belakang, Cloudflare akan tetap melayani versi cache lama (*stale*) kepada pengguna yang datang berikutnya, sementara satu proses tunggal bertugas mengambil data baru dari server asal.

Selain itu, pengelolaan *connection pooling* pada serverless SSR menjadi krusial. Karena fungsi edge atau serverless dijalankan secara instan dan dapat diskala dalam ribuan instans, membuka koneksi database baru di setiap permintaan akan langsung menghabiskan batas maksimal koneksi MySQL (`max_connections`). Di sinilah kita menggunakan proxy koneksi seperti **Prisma Accelerate** atau **PgBouncer / ProxySQL** untuk MySQL guna menampung dan membagikan koneksi database secara efisien di lingkungan terdistribusi.

Namun, bahkan dengan arsitektur terbaik sekalipun, kesalahan kecil dalam konfigurasi kerap kali menjadi bumerang yang meledakkan sistem dari dalam.

## 8. Jebakan Klasik & Cara Menghindarinya Sebelum Meledak

Selama bertahun-tahun menangani infrastruktur skala besar, saya telah melihat berbagai pola kegagalan yang berulang. Berikut adalah tiga jebakan klasik yang paling sering menjerumuskan tim engineering:

1. **Menggunakan `headers()` atau `cookies()` sembarangan di Server Component**: Memanggil fungsi dinamis seperti `headers()` di dalam komponen Next.js secara otomatis akan menonaktifkan seluruh mekanisme *Static Rendering* dan *ISR* untuk halaman tersebut, memaksa aplikasi kembali ke mode SSR penuh tanpa cache.
2. **Kebocoran Environment Variables di Klien**: Menyimpan kunci API rahasia (seperti secret token Cloudflare atau kredensial database) tanpa awalan `NEXT_PUBLIC_` memang aman dari sisi server, namun sering kali developer secara tidak sengaja mengimpor fungsi server ke dalam komponen klien (`'use client'`), yang berakibat fatal pada kebocoran keamanan data.
3. **TTL Terlalu Pendek Tanpa Alasan Valid**: Mengatur revalidate menjadi `1` detik pada halaman yang jarang berubah hanya akan membuat Cloudflare terus-menerus melakukan fetch ke origin, menghilangkan esensi dari CDN itu sendiri.

> [!TIP]
> Selalu gunakan perintah `next build` dan periksa laporan terminal secara teliti. Next.js memberikan indikator visual yang jelas (ikon lingkaran λ untuk Server/Dynamic, dan ikon lingkaran ● untuk Static) di setiap rute halaman yang dihasilkan. Pastikan halaman publik Anda bertuliskan simbol statis atau ISR, bukan sepenuhnya dinamis.

Sebelum kita merilis sistem ini ke production, ada satu tahapan mutlak yang harus dilewati: uji beban secara ekstrem untuk mengetahui titik batas keruntuhannya.

## 9. Uji Nyali: Mengukur Performa di Titik Batas

Jangan pernah percaya bahwa sistem Anda aman sebelum diuji menggunakan alat simulasi beban (*load testing tool*) seperti **k6** atau **Artillery**. Di lingkungan staging, kami mensimulasikan 50.000 virtual users (VUs) yang menghantam endpoint produk secara bersamaan selama 10 menit.

Berikut adalah skrip uji beban sederhana menggunakan k6 (`load-test.js`):

```javascript
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 10000 }, // Naikkan perlahan ke 10k pengguna
    { duration: '5m', target: 50000 }, // Tahan di 50k pengguna
    { duration: '2m', target: 0 },    // Turunkan kembali
  ],
};

export default function () {
  const res = http.get('https://staging.example.com/products/sepatu-lari-pro-X');
  
  check(res, {
    'status adalah 200': (r) => r.status === 200,
    'TTFB di bawah 50ms (Cache HIT)': (r) => r.timings.duration < 50,
  });
  
  sleep(1);
}
```

Dari hasil pengujian ini, kita dapat memantau metrik kunci seperti *p95 latency*, *error rate*, dan *cache hit ratio* di dashboard Cloudflare. Jika *cache hit ratio* Anda berada di bawah 90% untuk halaman publik, itu adalah tanda bahaya bahwa strategi cache Anda belum berjalan optimal. Perbaiki sebelum benar-benar dirilis ke publik dengan melengkapi checklist akhir berikut.

## 10. Catatan Lapangan & Checklist Sebelum Rilis

Sebagai penutup dari panduan komprehensif ini, simpan dan centang daftar periksa operasional berikut sebelum Anda menekan tombol *deploy* ke production:

- [ ] **Cache Rules Cloudflare**: Pastikan aturan *Cache Everything* sudah diterapkan pada pola URL aset statis dan halaman produk.
- [ ] **Environment Variables**: Verifikasi bahwa seluruh rahasia produksi (database URL, secret token) tersimpan aman di dashboard Cloudflare Workers dan tidak tercantum di repository publik.
- [ ] **Connection Pooling**: Pastikan batas maksimum koneksi database di backend tidak akan terlampaui saat terjadi lonjakan cache miss.
- [ ] **Monitoring & Alarms**: Atur sistem peringatan real-time via PagerDuty atau Slack jika persentase *HTTP 5xx errors* melewati ambang batas 0.5%.
- [ ] **Fallback UI**: Pastikan halaman *Error Boundary* dan *Not Found* di Next.js dirancang dengan baik untuk merespons kegagalan jaringan secara elegan.

Dengan merancang arsitektur hybrid rendering yang menggabungkan ketepatan ISR dan kecepatan distribusi Cloudflare Edge, Anda tidak hanya menyelamatkan infrastruktur dari keruntuhan di saat genting, tetapi juga memberikan pengalaman pengguna yang secepat kilat. Selamat membangun, dan semoga sistem Anda selalu stabil di bawah tekanan tertinggi!