Menjalankan Nuxt 3 di Cloudflare Workers memberi pendekatan yang berbeda dibanding deploy ke server Node tradisional. Aplikasi dirender dekat dengan pengguna, startup cenderung ringan, dan integrasi dengan layanan edge seperti KV, D1, serta Cache API bisa mengurangi latensi untuk skenario yang tepat. Namun, runtime edge juga membawa batasan penting: tidak semua modul Node bisa dipakai, akses filesystem terbatas, koneksi database tidak selalu bekerja seperti di server biasa, dan pola stateful perlu didesain ulang.

Artikel ini membahas praktik deploy Nuxt 3 ke Cloudflare Workers, cara memanfaatkan KV untuk cache/session sederhana, D1 untuk query data relasional ringan, serta kapan arsitektur edge rendering benar-benar menguntungkan dan kapan justru menambah kompleksitas.

Mengapa Nuxt 3 cocok untuk edge runtime

Nuxt 3 dibangun di atas Nitro, yang memang dirancang untuk menargetkan banyak runtime, termasuk server Node, serverless, dan edge runtime seperti Cloudflare Workers. Dalam konteks ini, yang dijalankan di Worker bukan server Node penuh, melainkan bundle yang disesuaikan untuk lingkungan service worker-like runtime.

Keuntungan utamanya:

  • Latency lebih rendah untuk rendering halaman yang dominan baca.
  • Distribusi global tanpa perlu mengelola cluster server di banyak region.
  • Integrasi native dengan cache edge, KV, dan binding ke D1.
  • Cocok untuk SSR/ISR ringan pada halaman konten, katalog, dokumentasi, dashboard baca-dominan, atau landing page dinamis.

Namun edge rendering tidak selalu lebih baik. Jika aplikasi bergantung pada library Node lama, koneksi database stateful, pekerjaan CPU berat, atau workflow backend kompleks, server tradisional sering lebih sederhana dan lebih mudah di-debug.

Arsitektur dasar: Nuxt 3 + Workers + KV + D1

Secara sederhana, arsitektur yang umum adalah sebagai berikut:

  • Nuxt 3/Nitro menangani SSR, route API, dan middleware.
  • Cloudflare Workers menjadi runtime eksekusi di edge.
  • KV dipakai untuk cache hasil render, metadata, feature flag, atau session ringan yang tidak butuh konsistensi kuat.
  • D1 dipakai untuk data relasional ringan sampai menengah, terutama pola baca lebih dominan daripada tulis.
  • Cache API/HTTP cache dipakai untuk mengurangi render ulang pada halaman yang sering diakses.

Hal penting untuk dipahami: KV bersifat eventually consistent, sehingga cocok untuk cache, lookup, dan data yang toleran terhadap propagasi. Sementara D1 lebih cocok untuk query SQL sederhana, data relasional, dan kebutuhan query yang lebih terstruktur daripada KV.

Persiapan proyek dan konfigurasi deploy

Konfigurasi Nuxt untuk preset Cloudflare

Pada umumnya, Anda ingin memastikan Nitro membangun output untuk target Cloudflare. Contoh konfigurasi sederhana di nuxt.config.ts:

export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-module'
  },
  runtimeConfig: {
    sessionSecret: '',
    public: {
      appName: 'Nuxt Edge App'
    }
  }
})

Pada beberapa setup, preset bisa berbeda tergantung toolchain yang digunakan. Intinya, build harus menargetkan runtime Cloudflare Worker, bukan Node server biasa. Setelah itu, gunakan Wrangler untuk deploy dan mengikat resource seperti KV dan D1.

Contoh wrangler.jsonc

Berikut contoh konfigurasi deployment yang realistis:

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "nuxt-edge-app",
  "main": ".output/server/index.mjs",
  "compatibility_date": "2025-03-01",
  "workers_dev": true,
  "kv_namespaces": [
    {
      "binding": "CACHE_KV",
      "id": "your_kv_namespace_id"
    }
  ],
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "app_db",
      "database_id": "your_d1_database_id"
    }
  ],
  "vars": {
    "NUXT_SESSION_SECRET": "change-me"
  }
}

Untuk secret yang sensitif, lebih aman gunakan wrangler secret put daripada menaruhnya langsung di file konfigurasi.

wrangler secret put NUXT_SESSION_SECRET

Build dan deploy

npm run build
wrangler deploy

Pada proyek nyata, pipeline CI/CD biasanya memisahkan environment seperti staging dan production dengan binding berbeda untuk KV, D1, dan secret.

Batasan runtime edge yang perlu dipahami sejak awal

Tidak semua API Node tersedia

Cloudflare Workers bukan runtime Node penuh. Beberapa library yang mengandalkan fs, net, tls, child_process, socket mentah, atau extension native biasanya tidak kompatibel. Kesalahan umum adalah menambahkan package yang terlihat “server-side”, padahal diam-diam membutuhkan API Node tertentu.

Praktiknya, pilih library yang:

  • Mendukung Fetch API.
  • Tidak bergantung pada filesystem runtime.
  • Tidak memakai koneksi TCP langsung.
  • Tersedia dalam bentuk ESM atau bundle yang ramah edge.

Untuk HTTP client, gunakan fetch bawaan bila memungkinkan. Untuk autentikasi, hashing, dan crypto, prioritaskan API yang kompatibel dengan Web Crypto.

Akses filesystem dan proses background terbatas

Di Worker, Anda tidak bisa mengandalkan penulisan file lokal atau direktori cache seperti pada server tradisional. Jika perlu menyimpan sesuatu, gunakan KV, R2, D1, atau cache edge. Pekerjaan background juga perlu mengikuti model Cloudflare, misalnya menggunakan mekanisme yang tersedia di platform, bukan daemon jangka panjang.

Batas CPU dan eksekusi

Walaupun cold start pada edge cenderung kecil, Worker tetap punya batas sumber daya. Hindari SSR yang memproses data besar, komputasi berat, atau transformasi sinkron panjang pada setiap request. Untuk halaman yang mahal dirender, gunakan strategi cache agresif dan precomputation bila memungkinkan.

Integrasi KV untuk cache dan session ringan

KV sebagai cache hasil render

Kasus paling cocok untuk KV adalah read-heavy content yang tidak membutuhkan konsistensi instan. Misalnya halaman produk, artikel, halaman kategori, atau fragmen data API yang berubah sesekali.

Contoh route API Nuxt untuk mengambil data dari KV lebih dulu, lalu fallback ke sumber lain:

export default defineEventHandler(async (event) => {
  const { cloudflare } = event.context
  const cacheKey = 'page:home'

  const cached = await cloudflare.env.CACHE_KV.get(cacheKey, 'json')
  if (cached) {
    return { source: 'kv', data: cached }
  }

  const freshData = {
    title: 'Beranda',
    updatedAt: new Date().toISOString()
  }

  await cloudflare.env.CACHE_KV.put(cacheKey, JSON.stringify(freshData), {
    expirationTtl: 300
  })

  return { source: 'origin', data: freshData }
})

Mengapa pola ini efektif? Karena request berikutnya tidak perlu memukul sumber data utama untuk setiap region. KV berperan sebagai distributed read cache yang murah dan cepat untuk lookup sederhana.

KV untuk session: boleh, tapi pahami trade-off

Menyimpan session di KV bisa berguna untuk aplikasi sederhana, terutama jika data session kecil dan tidak kritis terhadap konsistensi instan. Contohnya preferensi pengguna, state login ringan, atau token mapping. Namun ada batasannya:

  • Eventually consistent, sehingga update session mungkin tidak langsung terlihat di semua edge.
  • Tidak ideal untuk workflow yang sensitif terhadap race condition.
  • Session invalidation perlu dirancang dengan disiplin.

Untuk data autentikasi yang lebih sensitif, pendekatan yang sering lebih sederhana adalah signed cookie atau token stateless, lalu gunakan KV hanya untuk revocation list atau metadata tambahan.

Strategi invalidasi cache

Kesalahan umum di edge adalah meng-cache sesuatu tanpa rencana invalidasi. Pilihan invalidasi yang praktis:

  • TTL pendek untuk data yang sering berubah.
  • Versioned key, misalnya product:v42:123, sehingga deploy atau update cukup mengganti versi.
  • Tagging manual di level aplikasi, misalnya menyimpan daftar key yang terkait dengan suatu entitas.
  • Write-through invalidation: saat data diubah di D1, hapus atau ganti key KV yang berkaitan.

Versioned key sering paling aman karena menghindari masalah sinkronisasi penghapusan massal. Kekurangannya adalah potensi penumpukan key lama jika tidak dibersihkan berkala.

Query ke D1 dari Nuxt 3

Kapan D1 cocok digunakan

D1 cocok saat Anda butuh SQL ringan di edge: lookup data, daftar konten, relasi sederhana, dan query yang tidak terlalu berat. Ia sangat masuk akal untuk aplikasi baca-dominan seperti katalog, knowledge base, CMS ringan, direktori, atau halaman SSR yang mengambil sedikit data terstruktur per request.

Contoh query D1 di route server

export default defineEventHandler(async (event) => {
  const { cloudflare } = event.context
  const slug = getRouterParam(event, 'slug')

  const stmt = cloudflare.env.DB
    .prepare('SELECT id, slug, title, body, updated_at FROM articles WHERE slug = ? LIMIT 1')
    .bind(slug)

  const result = await stmt.first()

  if (!result) {
    throw createError({ statusCode: 404, statusMessage: 'Artikel tidak ditemukan' })
  }

  return result
})

Gunakan prepared statement agar query lebih aman dan rapi. Hindari merangkai SQL dengan interpolasi string mentah untuk input pengguna.

Pola read-heavy yang cocok

Untuk edge rendering, pola yang paling cocok biasanya:

  1. Request masuk ke Worker terdekat.
  2. Cek Cache API atau KV untuk HTML/data yang sudah siap.
  3. Jika tidak ada, ambil data inti dari D1.
  4. Render SSR sekali.
  5. Simpan hasil yang aman untuk di-cache ke edge cache atau KV.

Pola ini efektif karena D1 tidak perlu dipukul untuk setiap request. D1 menjadi source of truth ringan, sedangkan KV/cache menangani beban baca tinggi.

Yang kurang cocok adalah workload dengan:

  • Transaksi tulis intensif.
  • Query kompleks berbiaya tinggi pada setiap request.
  • Kebutuhan locking atau konsistensi ketat di banyak region.

Pengelolaan environment dan konfigurasi rahasia

Pisahkan environment sejak awal: local, staging, dan production. Jangan gunakan satu namespace KV atau satu database D1 untuk semua environment. Hal ini sering menyebabkan cache tercampur dan data uji masuk ke produksi.

Prinsip yang disarankan:

  • Vars untuk konfigurasi non-sensitif.
  • Secrets untuk token, secret session, API key.
  • Binding terpisah per environment untuk D1 dan KV.
  • Prefix key per environment jika benar-benar harus berbagi namespace, walau ini sebaiknya dihindari.

Di sisi Nuxt, ambil konfigurasi dari runtimeConfig dan jangan menaruh secret pada public config.

Cold start, performa, dan debugging

Cold start di edge

Cold start pada Workers umumnya lebih kecil dibanding model serverless tradisional yang menjalankan runtime server berat. Namun ini bukan alasan untuk membiarkan bundle membengkak. Semakin banyak dependency, polyfill, dan logic SSR berat, semakin besar risiko performa memburuk.

Tips praktis:

  • Kurangi dependency yang tidak benar-benar perlu.
  • Hindari library Node yang memaksa polyfill besar.
  • Cache hasil query dan render semaksimal mungkin.
  • Pecah route API agar tidak semua request memuat logic berat yang sama.

Debugging masalah umum

Beberapa masalah yang sering muncul saat deploy Nuxt ke Workers:

  • Module incompatibility: package mengakses API Node yang tidak ada.
  • Request context tidak tersedia: akses binding di tempat yang salah, bukan dari event/context.
  • Cache stale: key invalidation tidak konsisten.
  • Perbedaan lokal vs produksi: emulator lokal tidak selalu identik 100% dengan edge runtime.

Debugging yang efektif biasanya dimulai dengan memeriksa log Worker, meminimalkan dependency, dan menguji route server secara terpisah sebelum menyalahkan SSR penuh. Jika suatu library gagal hanya di deploy, cek apakah ia diam-diam bergantung pada API Node atau filesystem.

Kapan edge lebih unggul, dan kapan server tradisional lebih masuk akal

Edge lebih unggul ketika

  • Aplikasi read-heavy dengan banyak pengguna tersebar global.
  • Mayoritas request bisa dilayani dari cache atau lookup sederhana.
  • SSR membutuhkan data sedikit namun sensitif terhadap latensi.
  • Anda ingin menyatukan rendering, API ringan, dan cache global di satu platform.

Server tradisional lebih cocok ketika

  • Aplikasi sangat bergantung pada library Node native atau tool backend lama.
  • Butuh koneksi database penuh, connection pooling kompleks, atau transaksi berat.
  • Ada job CPU-bound, image/video processing, atau workflow stateful yang panjang.
  • Tim lebih membutuhkan kesederhanaan operasional dan debugging yang familiar.

Aturan praktis: jika mayoritas traffic Anda adalah baca, hasilnya bisa di-cache, dan data per request kecil, edge rendering sangat menarik. Jika aplikasi Anda dominan tulis, kompleks, dan banyak bergantung pada ekosistem Node tradisional, gunakan edge secara selektif atau tetap di server biasa.

Penutup

Deploy Nuxt 3 ke Cloudflare Workers bukan sekadar memindahkan SSR ke platform lain. Anda perlu menyesuaikan cara berpikir: state dibuat lebih ringan, cache menjadi komponen utama, dan pemilihan storage harus mengikuti karakteristik data. KV unggul untuk cache dan lookup global yang read-heavy, sedangkan D1 cocok untuk query SQL ringan yang mendukung rendering dinamis tanpa latensi besar dari origin terpusat.

Kunci keberhasilannya adalah memahami batasan runtime edge sejak awal: jangan memaksakan pola server Node tradisional apa adanya. Gunakan library yang kompatibel, desain invalidasi cache dengan sadar, pisahkan environment, dan optimalkan route baca agar memanfaatkan cache sebanyak mungkin. Dengan pendekatan ini, Nuxt 3 di Cloudflare Workers bisa menjadi pilihan yang sangat efektif untuk aplikasi modern yang mengutamakan latensi rendah dan distribusi global.