
מה זה
Cloudflare Workers היא פלטפורמת serverless של Cloudflare שמריצה את הקוד שלך על הרשת הגלובלית שלהם — היום ב-330+ ערים — בלי תשתית לנהל ובלי לבחור region. סביבת הריצה אינה container אלא V8 isolate: אותו מנגנון בידוד ש-Chrome משתמש בו כדי להפריד בין טאבים. instance יחיד של ה-runtime מריץ מאות או אלפי isolates ומחליף ביניהם, כך שלפי התיעוד הרשמי isolate עולה בערך פי מאה מהר יותר מ-Node process בתוך container או VM, וצורך סדר גודל פחות זיכרון בהפעלה. זו הסיבה שמודל ה-edge הזה כמעט מבטל את ה-cold start שמכאיב ב-Lambda.
סביב ה-runtime יושב סטאק primitives מלא, וכולם נקשרים ל-Worker דרך bindings: D1 (serverless SQLite), R2 (object storage תואם S3 ללא עמלות egress), KV (key-value eventually consistent לקריאות עתירות), Durable Objects (actors בעלי state, instance קנוני יחיד לכל ID עם consistency חזק), Queues (תורי הודעות) ו-Workers AI (הרצת inference על edge GPUs). שפות נתמכות: JavaScript, TypeScript, Python ו-Rust, וכל מה שמתקמפל ל-WASM.
שרשרת הכלים כולה חיה ב-monorepo אחד — cloudflare/workers-sdk — ברישיון כפול Apache-2.0 + MIT, עם למעלה מ-2,000 releases: ה-CLI הוא Wrangler (גרסה 4.101.0, נכון ליוני 2026), האמולטור המקומי הוא Miniflare (4.x), ו-scaffolder הפרויקטים הוא create-cloudflare / C3 (2.x). סביבת הריצה עצמה, workerd, היא פרויקט קוד-פתוח נפרד (Apache-2.0) שמניע גם את Miniflare מקומית וגם את ה-edge בפרודקשן — אותו binary בשני הקצוות.
איך זה עובד — ארכיטקטורה
בקשה נכנסת ל-PoP הקרוב ביותר למשתמש. ה-router של Cloudflare ממפה את ה-hostname ל-Worker שלך, ה-Worker מורם בתוך isolate באותו instance של ה-runtime שכבר רץ שם, וממנו הוא מדבר ישירות עם המשאבים שקשרת אליו: שאילתת D1 פונה לרפליקה הזמינה, קריאת R2 פותרת אובייקט מהאחסון, וקריאה ל-Durable Object מנותבת ל-instance הקנוני היחיד שאחראי על אותו ID — גם אם הבקשה הבאה לאותו ID מגיעה מיבשת אחרת. ה-Worker עצמו הוא stateless; ה-state חי ב-primitives.
מה שחשוב להבין לפני שבונים: ה-isolate חולק CPU עם isolates אחרים, ולכן המודל מטיל תקרת זמן CPU לכל invocation — לא wall-clock. אפשר לחכות שעה ל-fetch חיצוני; מה שנמדד הוא רק הזמן שבו הקוד שלך מעבד בפועל. ב-Free plan התקרה היא 10ms CPU לכל בקשה, ובתוכנית Paid ברירת המחדל היא 30 שניות וניתן להעלות עד 5 דקות CPU. הזיכרון מוגבל ל-128MB לכל isolate, וגודל הסקריפט הדחוס הוא עד 3MB ב-Free ו-10MB ב-Paid.
למה זה מנצח דווקא עבור landing pages, APIs ו-webhooks:
- כמעט בלי cold start — isolates עולים פי ~100 מהר יותר מ-container, כך שאין warmup tax על בקשה ראשונה.
- Free tier נדיב — 100,000 בקשות/יום ב-Workers, 10GB-month + 1M Class A + 10M Class B ב-R2 (ללא egress), 5GB אחסון D1 לכל חשבון.
- קובץ קונפיגורציה יחיד —
wrangler.tomlמגדיר את ה-Worker, כל binding וכל שם secret; אותו קובץ נכנס ל-git. - פיתוח מקומי אמיתי — Miniflare מדמה D1, R2, KV ו-Durable Objects מקומית, בלי Docker ובלי חיבור לחשבון.
התקנה
פקודה אחת מקימה פרויקט מקצה לקצה:
npm create cloudflare@latest
# or
pnpm create cloudflare@latest
# or
yarn create cloudflare@latest
C3 שואל שם, בוחר תבנית (Hello World, API, Hono, Astro, Next.js, Remix, SvelteKit, Workers AI…), מתקין תלויות ומציע לפרוס. Wrangler הוא ה-CLI שתעבוד איתו לאחר מכן:
# Add Wrangler to an existing project
npm install --save-dev wrangler
# Auth once
npx wrangler login
# Dev locally on Miniflare
npx wrangler dev
# Deploy globally
npx wrangler deploy
פקודות provisioning שימושיות:
npx wrangler d1 create my-db
npx wrangler r2 bucket create my-bucket
npx wrangler kv namespace create MY_KV
npx wrangler secret put RESEND_API_KEY
קונפיגורציה
הכל נמצא ב-wrangler.toml. יש להתייחס אליו כמקור האמת — הוא נשמר ב-git, זהה בין dev לפרודקשן, והוא המקום היחיד שבו bindings מוגדרים.
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2026-05-27"
compatibility_flags = ["nodejs_compat"]
# D1 serverless SQLite
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "12345678-1234-1234-1234-123456789012"
# R2 object storage
[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-bucket"
# KV namespace
[[kv_namespaces]]
binding = "KV_STORE"
id = "abcdef1234567890"
# Durable Object — single-instance stateful actor
[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
[[migrations]]
tag = "v1"
new_sqlite_classes = ["Counter"]
# Queues
[[queues.producers]]
queue = "email-jobs"
binding = "EMAIL_QUEUE"
# Vars and secrets
[vars]
ENVIRONMENT = "production"
# Secrets are added via: wrangler secret put RESEND_API_KEY
דוגמאות קוד
fetch handler מינימלי — המבנה הקנוני של Workers:
export default {
async fetch(request, env, ctx) {
return new Response("Hello, World!");
}
};
API לידים מבוסס D1 — מבנה אופייני של pipeline לטופס לידים: POST של payload JSON, ולידציה, כתיבה ל-D1, שליחת אימייל דרך Resend.
-- schema.sql
CREATE TABLE leads (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL,
phone TEXT,
message TEXT,
source TEXT,
created_at INTEGER DEFAULT (strftime('%s','now'))
);
CREATE INDEX idx_leads_created ON leads(created_at DESC);
-- Apply
npx wrangler d1 execute my-database --file=./schema.sql --remote
// src/index.ts
export interface Env {
DB: D1Database;
RESEND_API_KEY: string;
}
export default {
async fetch(req: Request, env: Env, ctx: ExecutionContext) {
if (req.method !== 'POST') return new Response('Method Not Allowed', { status: 405 });
const body = await req.json<{
name: string; email: string; phone?: string; message?: string;
}>();
if (!body.email || !body.name) {
return new Response('Missing fields', { status: 400 });
}
const id = crypto.randomUUID();
await env.DB
.prepare('INSERT INTO leads (id, name, email, phone, message, source) VALUES (?, ?, ?, ?, ?, ?)')
.bind(id, body.name, body.email, body.phone ?? null, body.message ?? null, 'landing')
.run();
// Fire-and-forget notification
ctx.waitUntil(
fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
'Authorization': `Bearer ${env.RESEND_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: 'noreply@example.com',
to: 'me@example.com',
subject: `New lead: ${body.name}`,
text: `${body.name} <${body.email}>\n${body.message ?? ''}`
})
})
);
return Response.json({ ok: true, id });
}
};
העלאת קבצים ל-R2 + קריאה חתומה:
export default {
async fetch(req: Request, env: { BUCKET: R2Bucket }) {
const url = new URL(req.url);
if (req.method === 'PUT') {
const key = url.pathname.slice(1);
await env.BUCKET.put(key, req.body, {
httpMetadata: { contentType: req.headers.get('content-type') || 'application/octet-stream' }
});
return Response.json({ key });
}
if (req.method === 'GET') {
const obj = await env.BUCKET.get(url.pathname.slice(1));
if (!obj) return new Response('Not found', { status: 404 });
return new Response(obj.body, {
headers: { 'content-type': obj.httpMetadata?.contentType ?? 'application/octet-stream' }
});
}
return new Response('Method Not Allowed', { status: 405 });
}
};
Durable Object — counter אחד strongly-consistent לכל room id, מושלם עבור rate-limiters, websocket rooms ו-state שיתופי:
export class Counter {
state: DurableObjectState;
constructor(state: DurableObjectState) { this.state = state; }
async fetch(req: Request) {
let count = (await this.state.storage.get<number>('n')) ?? 0;
count += 1;
await this.state.storage.put('n', count);
return Response.json({ count });
}
}
export default {
async fetch(req: Request, env: { COUNTER: DurableObjectNamespace }) {
const id = env.COUNTER.idFromName('global');
const stub = env.COUNTER.get(id);
return stub.fetch(req);
}
};
פיתוח מקומי עם Miniflare
ה-quality-of-life win הגדול ביותר באקוסיסטם Workers הוא ש-wrangler dev מעלה סימולטור מקומי מלא — Miniflare — שמדמה D1, R2, KV, Durable Objects, Queues ו-Workers AI על הדיסק. ללא Docker, ללא צורך ברישום. אותו wrangler.toml מניע גם את הסביבה המקומית וגם את הפרודקשן; שמות ה-bindings שכותבים בקוד מתורגמים לאמולטור המקומי ב-dev ולשירותי ה-edge האמיתיים בפריסה. ה-state נשמר בין הרצות ב-.wrangler/state/, כלומר מסד הנתונים D1 לפיתוח שורד אתחולים מחדש.
# Run locally with live-reload + persistent local state
npx wrangler dev
# Run against real remote bindings (still local code, but talks to prod D1/R2)
npx wrangler dev --remote
# Tail production logs
npx wrangler tail
גרסה ויכולות מרכזיות
נקודות שכדאי להכיר לפני שמתחילים:
- Wrangler 4.101.0 (נכון ליוני 2026) — ה-CLI הנוכחי; פלט רזה יותר, קונפיגורציה TOML-first נקייה, ופיתוח מקומי שמורם דרך Miniflare 4.x מתוך אותו monorepo.
- D1 (serverless SQLite) — עד 10 מסדים לחשבון ב-Free, 500MB לכל מסד ועד 5GB סך הכל; שחזור Time Travel (point-in-time) עד 7 ימים ב-Free, ועד 50 שאילתות לכל invocation. הדגם המומלץ הוא scale-out למסדים קטנים, לא מסד ענק יחיד.
- R2 ללא egress — משלמים על אחסון ועל פעולות (Class A/B), לעולם לא על bandwidth יוצא; ה-Free tier הוא 10GB-month, מיליון פעולות Class A ו-10 מיליון Class B. זה ה-killer feature מול S3.
- Durable Objects — instance יחיד strongly-consistent לכל ID, הבסיס ל-rate-limiters, WebSocket rooms ו-state שיתופי בזמן אמת.
- Workers AI — הרצת inference (Llama, Whisper, Stable Diffusion ועוד) על edge GPUs דרך binding אחד, בלי לנהל GPU.
- workerd בקוד פתוח — אותה סביבת ריצה שמניעה גם את Miniflare מקומית וגם את ה-edge, Apache-2.0; אפשר אפילו לאחסן אותה בעצמך.
מתי להשתמש — ומגבלות
בשימוש יומיומי זה הצירוף שהכי קל לחזור אליו עבור landing page קטן: Vercel לאתר הסטטי + Cloudflare Worker + D1 לאחסון + Resend לאימייל, חתום HMAC מקצה לקצה. ה-free tier מכסה חודשים של תנועה אמיתית, פריסה היא פקודה אחת, ואין Docker, אין VPC, אין Lambda warmup ואין cold-start tax. מניסיון, המנוף הגדול הוא שאותו wrangler.toml רץ זהה בין dev לפרודקשן, כך שמה שעובד מקומית מתנהג אותו דבר על ה-edge.
איפה Workers מפסיק להיות התשובה הנכונה: כל עומס שדורש זמן CPU ממושך — זכור שה-Free plan חוסם ב-10ms CPU לכל בקשה ו-Paid ב-30 שניות (עד 5 דקות) — וכן משקלי מודל ML כבדים שלא נכנסים ל-128MB, או סמנטיקת קבצי POSIX מדויקת. בנקודות האלה VM אמיתי, container, או Supabase Edge מתאימים יותר. כדאי גם לזכור ש-KV הוא eventually consistent (לא לסמוך עליו ל-state טרנזקציוני), ו-D1 מתוכנן ל-scale-out על מסדים קטנים ולא למסד ענק יחיד. לכל השאר — טפסים, APIs, webhooks, cron ו-scheduled jobs, rate-limits לפי ID דרך Durable Objects — Workers הוא בחירה שקשה להתחרות בה.