Cloudflare Workers menjalankan JavaScript-mu di jaringan Cloudflare, di lebih dari 300 kota, sehingga kode itu jalan di data center yang paling dekat dengan pengunjung. Tempat-tempat itu disebut edge, dan menjalankan kode di sana disebut edge computing. Bayangin minimarket di ujung gang dan gudang pusatnya. Kasir minimarket bisa menjawab sendiri urusan kecil: cek harga, tukar kupon, menunjukkan arah. Pesanan besar diteruskan ke gudang pusat. Workers adalah kasir itu, dan gudang pusatnya adalah server origin-mu, web-1. Cloudflare sudah berdiri di depan catatan-api sejak pelajaran Caching Strategies, jadi Worker tinggal dipasang di jalur yang sama.
🧪 Tebakan cepat: pengunjung di Jakarta membuka link pendek
https://catatan.example.com/s/k7x2. Apakah request itu sampai keweb-1? Tebak dulu, jawabannya ada di bagian "Binding: KV, D1, dan Durable Objects".
Worker pertama: fetch(request, env, ctx)
Worker catatan-edge dipasang di route catatan.example.com/*, jadi semua request ke domain itu lewat dia dulu:
// src/index.js
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// 1. Dijawab sendiri di edge
if (url.pathname === "/api/hello") {
return Response.json({ message: "Hello from edge!", colo: request.cf?.colo });
}
// 2. Link pendek: dibaca dari KV di edge
if (url.pathname.startsWith("/s/")) {
const kode = url.pathname.slice(3);
const tujuan = await env.LINKS.get(kode);
if (tujuan === null) {
return new Response("Link tidak ditemukan", { status: 404 });
}
return Response.redirect(tujuan, 302);
}
// 3. Path lain: diteruskan apa adanya ke origin (web-1)
return fetch(request);
},
};
fetch(request, env, ctx)dipanggil sekali per request.requestadalah objectRequeststandar web, sama dengan yang ada di browser. Yang dikembalikan harusResponse.envberisi binding: sambungan ke resource Cloudflare seperti KV, D1, atau secret.ctx.waitUntil(promise)membiarkan kerja kecil (misalnya kirim log) selesai setelah response dikirim.request.cfberisi info dari Cloudflare tentang request itu:colo(kode data center, misalnyaCGKuntuk Jakarta),country,city.return fetch(request)meneruskan request ke origin. Tanpa baris ini, path lain seperti/aboutatau/catatan/populergak pernah sampai keweb-1.
Jalan di dekat user
Pengunjung di Jakarta masuk ke data center CGK, di Surabaya ke SUB, di Tokyo ke NRT. Worker yang sama jalan di ketiganya, jadi jawaban /api/hello berisi "colo":"CGK" untuk yang satu dan "colo":"NRT" untuk yang lain. Angka contoh dari Lab, pengunjung di Jakarta:
| Request | Siapa yang menjawab | Waktu (contoh) |
|---|---|---|
/api/hello |
Worker di CGK | 4 ms ke edge + ±1 ms kerja = 5 ms |
/s/k7x2 |
Worker di CGK, baca KV | 4 + 1 + 1 = 6 ms |
/catatan/populer |
web-1 lewat fetch(request) (cache MISS) |
4 + 30 ke origin + 40 kerja Express = 74 ms |
Yang dijawab di edge gak perlu menyeberang ke origin. Makin jauh pengunjung dari web-1, makin besar bedanya: dari Tokyo, edge ke origin jadi 78 ms.
V8 isolate, bukan container
Lambda menyalakan container berisi runtime Node.js untuk tiap environment, dan cold start-nya ratusan milidetik sampai sekitar 1 detik (100 ms sampai 1 detik). Workers memakai V8 isolate: ruang terisolasi di dalam satu proses mesin JavaScript V8, mesin yang sama dengan Chrome. Satu proses bisa menampung ribuan isolate milik banyak pelanggan, masing-masing dengan memory-nya sendiri dan gak bisa saling intip. Membuat isolate baru cuma butuh beberapa milidetik (Cloudflare menyebut di bawah 5 ms), jadi cold start hampir gak terasa.
Harganya: Workers bukan Node.js penuh. Yang tersedia adalah Web API (fetch, Request, Response, URL, crypto.subtle), ditambah sebagian API Node lewat flag nodejs_compat. Memory tiap isolate 128 MB.
Binding: KV, D1, dan Durable Objects
Binding ditulis di wrangler.toml, lalu muncul di env:
- KV (key-value): simpanan string per key, disalin ke banyak lokasi supaya cepat dibaca di mana pun.
await env.LINKS.get("k7x2")mengembalikan string, ataunullkalau key-nya gak ada. Menulis:await env.LINKS.put("k7x2", url, { expirationTtl: 3600 }), hilang sendiri setelah 1 jam. - D1: database SQLite milik Cloudflare, untuk data relasional dengan query SQL:
await env.DB.prepare("SELECT * FROM catatan WHERE id = ?").bind(42).first(). - Durable Objects: object dengan state dan storage sendiri yang hidup di satu lokasi. Semua request untuk object yang sama dilayani di satu tempat, satu per satu, jadi hitungannya selalu konsisten. Cocok untuk rate limiter per user, counter, atau ruang chat WebSocket.
Kembali ke tebakan: /s/k7x2 dijawab Worker di CGK dengan redirect 302 ke https://catatan.example.com/catatan/populer, dari data di KV. Request link pendek itu sendiri gak sampai ke web-1. Itu jawaban tebakannya. Baru browser yang mengikuti redirect ke /catatan/populer, dan request kedua itu yang diteruskan ke origin.
KV itu eventually consistent: tulisan baru bisa butuh sekitar 60 detik atau lebih sebelum terbaca di lokasi lain. Bagus untuk data yang sering dibaca dan jarang ditulis seperti link pendek. Untuk hitungan yang harus tepat, seperti rate limiter, pakai Durable Objects.
Batas CPU time
Workers membatasi CPU time, yaitu waktu prosesor benar-benar bekerja untuk satu request. Waktu menunggu fetch ke origin atau ke KV gak dihitung. Per 2025: paket Free 10 ms CPU per request, paket berbayar bawaannya 30 detik dan bisa dinaikkan sampai 5 menit (cek halaman Limits di docs Cloudflare, angkanya pernah berubah). Worker catatan-edge cuma memakai sekitar 1 ms, jauh di bawah batas. Kerja berat seperti mengubah ukuran gambar besar lebih cocok di tempat lain.
Deploy dengan wrangler
wrangler adalah CLI resmi Workers. Config-nya:
# wrangler.toml
name = "catatan-edge"
main = "src/index.js"
compatibility_date = "2025-09-01"
workers_dev = false
routes = [
{ pattern = "catatan.example.com/*", zone_name = "example.com" }
]
[[kv_namespaces]]
binding = "LINKS"
id = "06779da6940b431db6e566b4846d64db"
Output npx wrangler deploy (wrangler 4.80; baris judul dipangkas, id versi contoh):
Total Upload: 0.63 KiB / gzip: 0.36 KiB
Your Worker has access to the following bindings:
Binding Resource
env.LINKS (06779da6940b431db6e566b4846d64db) KV Namespace
Uploaded catatan-edge (2.14 sec)
Deployed catatan-edge triggers (0.83 sec)
catatan.example.com/* (zone name: example.com)
Current Version ID: 5b0c7e1a-3f2d-4c8b-9a6e-1d4f7b2c9e30
env.LINKS (...) KV Namespace: bindingLINKSdi config sekarang tersedia sebagaienv.LINKS.catatan.example.com/* (zone name: example.com): route tempat Worker dipasang.workers_dev = falsemembuatnya gak ikut terbit di alamat*.workers.dev.- Untuk mencoba di laptop dulu,
npx wrangler devmenjalankan Worker yang sama secara lokal.
⚠️ Jebakan yang sering ketemu
- Menyimpan state di variabel global. Tiap isolate punya salinan sendiri, dan isolate bisa dibuang kapan saja. Counter di variabel global menghitung sebagian request saja. Pakai Durable Objects.
- Menganggap KV langsung konsisten. Link yang baru ditulis bisa masih
nulldi lokasi lain selama sekitar satu menit. - Lupa
return fetch(request)di akhir. Routecatatan.example.com/*menangkap semua path, jadi tanpa baris itu/catatan/populergak pernah sampai keweb-1. - Kerja CPU berat di Worker. Free plan cuma 10 ms CPU. Menunggu
fetchboleh lama, menghitung gak boleh.
TL;DR: Cloudflare Workers menjalankan fetch(request, env, ctx) di data center terdekat dengan pengunjung (edge), di lebih dari 300 kota. Handler menerima Request standar web dan mengembalikan Response; request.cf.colo memberi tahu data center mana yang menjawab, dan return fetch(request) meneruskan path lain apa adanya ke origin. Workers memakai V8 isolate, bukan container, jadi cold start-nya di bawah 5 ms, sedangkan Lambda 100 ms sampai 1 detik, tapi bukan Node.js penuh. Binding di env: KV (cepat dibaca di mana pun, eventually consistent), D1 (SQLite), Durable Objects (state di satu lokasi, cocok untuk rate limiter). Batasnya CPU time (Free 10 ms per request); waktu menunggu fetch gak dihitung. Deploy dengan npx wrangler deploy, yang mencetak binding, route, dan id versi.