Memilih Vercel Functions, Edge, atau backend persisten untuk SaaS harus dimulai dari bentuk beban kerja: durasi request, lokasi pengguna dan database, kebutuhan koneksi yang hidup lama, serta tingkat kompleksitas domain bisnis. Vercel Functions cocok untuk banyak API HTTP yang stateless, Edge runtime cocok untuk keputusan ringan yang sensitif terhadap latency di dekat pengguna, sedangkan backend persisten diperlukan ketika aplikasi membutuhkan worker jangka panjang, WebSocket, koneksi database yang lebih terkontrol, atau proses bisnis yang kompleks.
Kesalahan umum adalah menempatkan seluruh backend di satu runtime hanya karena deployment awalnya mudah. Arsitektur yang baik biasanya bersifat hybrid: Vercel menangani frontend dan sebagian endpoint yang dekat dengan pengalaman pengguna, sementara layanan eksternal menangani proses yang membutuhkan proses hidup lebih lama atau kontrol infrastruktur lebih besar.
Ringkasan: pilih berdasarkan bentuk pekerjaan
- Vercel Functions: pilih untuk API HTTP stateless, webhook, BFF (backend for frontend), validasi, dan operasi CRUD dengan durasi yang terkendali.
- Edge runtime: pilih untuk routing, autentikasi awal, personalisasi ringan, eksperimen, redirect, dan respons yang perlu dekat dengan pengguna tanpa ketergantungan berat pada runtime Node.js atau database jauh.
- Backend persisten eksternal: pilih untuk WebSocket, consumer queue, scheduler yang andal, pekerjaan lama, proses CPU/memori lebih berat, koneksi internal, dan domain bisnis yang tumbuh kompleks.
Runtime bukan sekadar pilihan deployment. Ia menentukan batas waktu eksekusi, model koneksi, cara menskalakan layanan, cara melakukan observability, dan seberapa mudah domain bisnis diuji serta dikembangkan oleh tim.
Membandingkan Vercel Functions, Edge, dan backend persisten
| Aspek | Vercel Functions | Edge runtime | Backend persisten eksternal |
|---|---|---|---|
| Pola eksekusi | Request-response, stateless, diskalakan per invokasi | Request-response di lokasi edge, stateless | Proses atau container yang dapat hidup lebih lama |
| Latency pengguna | Baik bila fungsi dan dependency berada dekat pengguna/data | Sangat baik untuk logika ringan di dekat pengguna | Bergantung region deployment dan topologi jaringan |
| Database | Cocok untuk query singkat; desain pool dan koneksi perlu diperhatikan | Terbatas oleh kompatibilitas runtime; hindari akses DB jauh pada jalur kritis | Kontrol koneksi, pool, driver, dan jaringan paling besar |
| Job berdurasi panjang | Tidak ideal; batas eksekusi dan retry harus dipertimbangkan | Tidak cocok | Cocok dengan worker, queue, checkpoint, dan retry |
| WebSocket | Bukan pilihan utama untuk koneksi dua arah yang bertahan lama | Bukan pilihan utama | Cocok melalui server/protokol realtime yang dikelola khusus |
| Skalabilitas | Otomatis untuk lonjakan request HTTP | Otomatis dan terdistribusi untuk logika ringan | Perlu autoscaling, kapasitas minimum, dan operasi sendiri/managed |
| Kompatibilitas API | Lebih sesuai untuk ekosistem Node.js, sesuai runtime yang dipilih | Mengandalkan Web API dan tidak selalu mendukung seluruh API Node.js | Bebas memilih runtime, library, daemon, dan protokol |
| Operasional | Rendah | Rendah, tetapi debugging lingkungan terdistribusi perlu disiplin | Lebih tinggi, tetapi kontrol lebih besar |
Tabel ini bukan aturan mutlak. Misalnya, endpoint sederhana yang memanggil database dapat bekerja di Vercel Functions. Namun, jika endpoint tersebut berkembang menjadi orkestrasi pembayaran, sinkronisasi vendor, pengiriman file, dan beberapa retry, worker persisten biasanya menjadi pilihan yang lebih aman.
Menentukan runtime dari pola trafik dan latency
Trafik burst, request pendek, dan API stateless
Vercel Functions sesuai ketika traffic tidak rata, API dipanggil secara sporadis atau melonjak saat kampanye, dan setiap request dapat selesai secara mandiri. Contohnya adalah membuat checkout session, menerima webhook, mengambil profil pengguna, atau menghasilkan signed URL untuk object storage.
Rancang endpoint agar stateless dan idempoten. Jangan mengandalkan variabel global di memori untuk sesi, lock, cache, atau status pekerjaan, karena instance dapat dibuat, dihentikan, atau diparalelkan kapan saja. Simpan state pada database, cache eksternal, object storage, atau sistem queue.
Latency sangat rendah di dekat pengguna
Edge runtime berguna bila keputusan dapat dibuat dari request itu sendiri atau dari data yang cepat diakses: cookie, header, token, konfigurasi kecil, feature flag, atau cache. Contoh yang baik adalah mengarahkan pengguna ke locale yang benar, memblokir request berdasarkan aturan sederhana, atau memilih varian eksperimen.
Jangan menganggap Edge selalu mempercepat seluruh API. Bila fungsi edge berada dekat pengguna tetapi harus menunggu query ke database di satu region yang jauh, total latency tetap didominasi perjalanan ke database. Dalam kasus itu, edge dapat menambah hop dan kompleksitas tanpa manfaat berarti.
Traffic stabil atau kebutuhan kapasitas yang dapat diprediksi
Backend persisten sesuai untuk trafik stabil dengan kebutuhan koneksi, cache lokal, atau worker yang terus aktif. Layanan seperti API inti, gateway realtime, consumer queue, dan pipeline pemrosesan dapat berjalan dalam region yang sama dengan database. Kedekatan ini sering lebih penting daripada menempatkan logika awal di edge.
Database, regionalitas, dan batas koneksi
Letakkan komputasi yang sering mengakses database sedekat mungkin dengan database. Bila database hanya berada di satu region, endpoint mutasi data utama biasanya sebaiknya berjalan di region yang sama atau pada backend persisten di jaringan yang dekat. Ini mengurangi latency, biaya transfer, dan risiko timeout berantai.
Vercel Functions dapat mengakses database eksternal, tetapi koneksi harus diperlakukan sebagai sumber daya terbatas. Lonjakan concurrency dapat meningkatkan jumlah koneksi secara cepat. Gunakan mekanisme pooling atau proxy koneksi yang kompatibel dengan database Anda, batasi query per request, dan pastikan transaksi sesingkat mungkin.
Edge runtime memerlukan perhatian tambahan karena tidak semua driver database yang bergantung pada API Node.js cocok dengan runtime edge. Jika memakai edge, preferensikan API HTTP database/gateway yang memang mendukungnya, atau batasi edge pada validasi dan routing lalu teruskan operasi data ke API regional.
- Data residency: tentukan region tempat data pelanggan boleh diproses dan disimpan sebelum memilih lokasi eksekusi.
- Read path dan write path: pembacaan yang dapat di-cache bisa berada dekat pengguna; penulisan biasanya harus dekat primary database atau melewati API domain.
- Consistency: jangan melayani hasil yang menuntut konsistensi kuat dari replika yang memiliki lag tanpa menjelaskan konsekuensinya pada produk.
- Connection storm: pantau jumlah koneksi database saat traffic burst, bukan hanya latency endpoint.
Pekerjaan lama, tugas latar belakang, dan WebSocket
Request HTTP sebaiknya tidak menunggu pekerjaan yang durasinya tidak pasti, seperti ekspor laporan besar, transcoding media, sinkronisasi ribuan record, pengiriman kampanye, atau pemanggilan API vendor dengan retry. Walaupun sebuah function mungkin dapat menyelesaikan sebagian pekerjaan tersebut, desain ini rentan terhadap batas waktu, duplikasi eksekusi, kegagalan di tengah proses, dan observability yang buruk.
Pola yang lebih tahan gagal adalah: API memvalidasi request, menyimpan intent atau job, memasukkannya ke queue, lalu worker persisten memprosesnya. API segera mengembalikan identifier job; frontend melakukan polling, menerima event realtime dari provider khusus, atau membaca status dari database.
POST /api/reports/export
- validasi pengguna dan parameter
- buat record export dengan status: queued
- kirim pesan { exportId } ke queue
- respons: 202 Accepted + exportId
Worker persisten
- ambil pesan dari queue
- ubah status menjadi processing
- buat file ke object storage
- ubah status menjadi completed atau failed
- simpan error yang aman untuk ditampilkan ke pengguna
Worker harus idempoten karena sistem queue umumnya dapat mengirim ulang pesan. Gunakan kunci idempotensi atau status transition yang atomik agar job yang terkirim dua kali tidak menagih pelanggan dua kali atau membuat dua file ekspor.
Untuk WebSocket, presence, collaborative editing, dan notifikasi dua arah, gunakan layanan realtime terkelola atau backend persisten yang memang dirancang menahan koneksi lama. Vercel Functions dan Edge runtime lebih tepat menjadi endpoint HTTP pendukung, misalnya untuk membuat token kanal realtime atau memvalidasi otorisasi.
Matriks keputusan arsitektur SaaS
| Kebutuhan utama | Pilihan awal | Catatan desain |
|---|---|---|
| Landing page, SSR, API formulir singkat | Vercel + Vercel Functions | Simpan state di layanan eksternal; lindungi endpoint dari abuse. |
| Redirect locale, auth gate, A/B test, routing tenant | Edge runtime | Jaga logika kecil; hindari query database jarak jauh di jalur kritis. |
| CRUD SaaS dengan database regional | Vercel Functions atau API eksternal dekat DB | Pilih berdasarkan kompleksitas query, koneksi, dan kebutuhan domain. |
| Webhook pembayaran | Vercel Functions + queue | Verifikasi signature, deduplikasi event, dan proses bisnis di worker. |
| Ekspor, ETL, AI batch, media processing | Queue + worker persisten | Gunakan checkpoint, retry terbatas, dead-letter handling, dan object storage. |
| Chat, presence, kolaborasi realtime | Backend/provid er realtime persisten | Jangan menggantungkan koneksi hidup lama pada function request-response. |
| Domain pembayaran, billing, atau workflow kompleks | Backend persisten terpisah | Isolasi model domain, audit trail, kontrak API, dan deployment lifecycle. |
Topologi hybrid yang praktis
Topologi hybrid memungkinkan tim mempertahankan kecepatan deployment frontend Vercel tanpa memaksa semua domain masuk ke function. Vercel menangani aplikasi web, cache, rendering, dan endpoint tipis. Backend eksternal menangani API domain inti serta worker.
Browser
|
+--> Vercel: aplikasi web, SSR, aset statis, middleware/edge ringan
| |
| +--> Vercel Function: BFF, callback auth, webhook ingress
|
+--> API domain eksternal (region dekat database)
|
+--> PostgreSQL / database utama
+--> Redis atau cache
+--> Queue
+--> Worker persisten
+--> Object storage / layanan realtime
Dalam model ini, BFF di Vercel tidak harus menjadi proxy untuk semua endpoint. Gunakan BFF untuk kebutuhan yang memang terkait UI, seperti agregasi beberapa respons, pembacaan session, atau menyembunyikan detail layanan internal. Untuk operasi domain inti, frontend dapat memanggil API domain melalui hostname khusus dengan autentikasi, CORS, rate limit, dan kontrak yang jelas.
// Contoh route handler sebagai BFF tipis: meneruskan identitas pengguna,
// bukan memindahkan seluruh logika billing ke frontend deployment.
export async function POST(request) {
const session = await getSessionFromRequest(request);
if (!session) return Response.json({ error: "unauthorized" }, { status: 401 });
const body = await request.json();
const response = await fetch(process.env.BILLING_API_URL + "/v1/checkout", {
method: "POST",
headers: {
"content-type": "application/json",
"x-user-id": session.userId,
"x-request-id": crypto.randomUUID()
},
body: JSON.stringify(body)
});
return new Response(response.body, {
status: response.status,
headers: { "content-type": "application/json" }
});
}
Contoh tersebut mengasumsikan backend billing memverifikasi identitas layanan atau token internal; header saja bukan mekanisme keamanan yang cukup jika endpoint dapat diakses dari jaringan publik. Terapkan autentikasi service-to-service, validasi audience, rotasi secret, dan pembatasan network bila tersedia.
Isolasi domain bisnis dan maintainability
Pemisahan backend tidak selalu berarti memecah aplikasi menjadi banyak microservice. Satu backend persisten berbentuk modular monolith sering lebih mudah dirawat daripada banyak function yang masing-masing mengakses tabel yang sama secara langsung.
Isolasi domain layak dipertimbangkan ketika billing, entitlement, audit, sinkronisasi integrasi, atau workflow memiliki aturan sendiri, kebutuhan retry berbeda, dan risiko bisnis lebih tinggi. Buat batas melalui kontrak API atau command/event yang eksplisit. Hindari frontend, function webhook, dan worker mengubah tabel domain yang sama dengan aturan bisnis yang berbeda-beda.
- Simpan aturan otorisasi dan transition status di satu lapisan domain.
- Gunakan outbox atau event terstruktur bila perubahan database harus memicu job eksternal.
- Versikan kontrak API dan event saat ada banyak konsumen.
- Tambahkan correlation ID dari browser, function, API, queue, hingga worker.
Trade-off: biaya, observability, lock-in, dan operasi
Skalabilitas dan biaya
Serverless dan edge mengurangi kebutuhan mengelola server, tetapi biaya biasanya berkaitan dengan jumlah invokasi, waktu/komputasi eksekusi, transfer data, serta layanan pendukung. Backend persisten menambah biaya kapasitas minimum, operasi, dan autoscaling, tetapi dapat lebih efisien untuk koneksi panjang atau beban stabil.
Hitung biaya secara konseptual per jalur transaksi, bukan hanya per layanan:
Biaya transaksi ≈
request frontend + eksekusi API + pembacaan/penulisan database
+ transfer jaringan + cache + pesan queue + waktu worker
+ penyimpanan file + egress ke pengguna atau vendor
Lalu kalikan dengan volume per fitur: jumlah page view, API request, event webhook, job, ukuran file, dan koneksi realtime. Buat tiga skenario: normal, puncak yang realistis, dan kegagalan vendor yang memicu retry. Retry tanpa batas dapat menjadi sumber biaya dan beban terbesar pada sistem event-driven.
Observability
Pada arsitektur hybrid, masalah sering muncul di batas antar layanan: function berhasil menerima request tetapi queue gagal menerima pesan, worker selesai tetapi status database tidak berubah, atau edge mengarahkan pengguna ke origin yang salah. Gunakan log terstruktur, trace ID, metrik latency per dependency, metrik error per jenis job, dan alarm untuk queue backlog serta kegagalan retry.
Jangan mencatat token, isi pembayaran, atau data pribadi dalam log. Masking dan kebijakan retensi log merupakan bagian dari desain, terutama pada SaaS B2B.
Vendor lock-in
Vercel memberi integrasi deployment dan frontend yang nyaman, tetapi kode yang sangat bergantung pada perilaku runtime, konfigurasi regional, atau integrasi khusus platform akan lebih mahal dipindahkan. Kurangi lock-in yang tidak perlu dengan menempatkan logika domain di package atau layanan yang dapat dijalankan di lingkungan standar, menggunakan HTTP/event contract, dan menyimpan data pada layanan dengan strategi ekspor yang jelas.
Lock-in tidak selalu buruk. Pilih secara sadar bila produktivitas yang diperoleh lebih besar daripada biaya migrasi yang mungkin terjadi. Yang perlu dihindari adalah lock-in tidak disengaja pada bagian paling kritis dari bisnis.
Indikator bahwa Anda perlu memigrasikan sebagian backend
- Request mulai melakukan polling internal, sleep, atau menunggu proses eksternal yang lama.
- Anda membutuhkan daemon, consumer queue kontinu, cron yang harus sangat andal, atau koneksi WebSocket jangka panjang.
- Lonjakan traffic menyebabkan tekanan koneksi database atau timeout yang sulit direproduksi.
- Logika domain tersebar di route handler, webhook, dan frontend sehingga aturan status tidak konsisten.
- Tim membutuhkan debugging lokal, profiling, network policy, atau dependency native yang tidak sesuai dengan runtime saat ini.
- Latency mutasi data tinggi karena compute berada jauh dari database utama.
- Kebutuhan audit, compliance, atau isolasi tenant menuntut kontrol jaringan dan deployment lebih ketat.
Migrasi tidak perlu berupa rewrite. Pindahkan terlebih dahulu jalur yang paling bermasalah: worker ekspor, webhook processor, gateway realtime, atau modul billing. Pertahankan frontend dan endpoint sederhana di Vercel, lalu ukur kembali latency, error rate, backlog, serta biaya per transaksi.
Checklist keputusan sebelum implementasi
- Petakan setiap endpoint: apakah request dapat selesai cepat dan stateless?
- Tentukan lokasi database, kebutuhan residency data, dan jalur read/write utama.
- Identifikasi koneksi hidup lama, pekerjaan asinkron, serta proses yang membutuhkan retry.
- Ukur dependency paling lambat; jangan mengoptimalkan edge sebelum memahami latency database dan vendor API.
- Tetapkan batas domain: siapa yang memiliki aturan billing, entitlement, dan audit?
- Rancang observability lintas frontend, API, queue, worker, dan database sejak awal.
- Modelkan biaya pada skenario normal, puncak, dan retry akibat kegagalan.
Pilihan terbaik bukan runtime yang paling mudah dideploy, melainkan kombinasi runtime yang membuat jalur kritis tetap cepat, proses bisnis tetap andal, dan sistem tetap mudah diubah ketika SaaS bertumbuh.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!