Kết luận nhanh
- Dùng Workers khi bạn cần chạy logic ở edge: API backend, proxy, xác thực, middleware, job handler — không cần serve file tĩnh
- Dùng Pages khi bạn có frontend: Next.js, Astro, SvelteKit, React SPA — Pages lo cả phần hosting lẫn phần server (Pages Functions chính là Workers bên dưới)
- Không phải chọn một trong hai: nhiều dự án dùng Pages cho frontend + Workers riêng cho backend API, rồi bind chung KV/D1/R2
Bảng so sánh nhanh
| Workers | Pages | |
|---|---|---|
| Mục đích chính | Serverless function tại edge | Static hosting + Functions |
| Cách deploy | wrangler deploy |
Git push (hoặc wrangler pages deploy) |
| Serve file tĩnh | Không (phải kết hợp R2 hoặc KV) | Có — tự động từ build output |
| Server-side logic | Toàn bộ là logic | Pages Functions (Workers bên dưới) |
| Framework hỗ trợ | Không có sẵn | Next.js, Astro, SvelteKit, Remix... |
| Bind KV/D1/R2/Queue | Có | Có (trong Pages Functions) |
| Cron trigger | Có ([triggers] trong wrangler.toml) |
Không |
| Free tier requests | 100.000 req/ngày | Không giới hạn requests (vô hạn) |
| Free tier build | Không áp dụng | 500 build/tháng |
| Custom domain | Có | Có |
| Preview deployment | Không | Có (mỗi branch/PR tạo preview URL) |
Workers là gì và làm được gì
Workers là nền tảng serverless function của Cloudflare chạy ở edge — tức là code của bạn chạy trên datacenter Cloudflare gần người dùng nhất, không phải trên một server cố định.
Mỗi Worker nhận một HTTP request, xử lý, và trả về response. Không có server, không có container, không có cold start đáng kể.
Worker cơ bản trông như thế này
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/api/ping") {
return Response.json({ ok: true, ts: Date.now() });
}
return new Response("Not found", { status: 404 });
},
};
Deploy bằng:
wrangler deploy
Workers phù hợp cho bài toán nào
API backend thuần
Khi app mobile hoặc SPA cần một API nhẹ, không muốn dựng server riêng:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method === "POST" && new URL(request.url).pathname === "/api/contact") {
const body = await request.json<{ email: string; message: string }>();
await env.DB.prepare("INSERT INTO contacts (email, message) VALUES (?, ?)")
.bind(body.email, body.message)
.run();
return Response.json({ ok: true });
}
return new Response("Not found", { status: 404 });
},
};
Proxy và middleware
Chèn logic trước khi request đến origin server: xác thực token, rate limit, rewrite URL, thêm header:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const token = request.headers.get("Authorization");
if (!token || !(await verify(token, env.JWT_SECRET))) {
return new Response("Unauthorized", { status: 401 });
}
return fetch(request); // forward to origin
},
};
Cron job tại edge
Workers có thể chạy định kỳ không cần request từ người dùng:
# wrangler.toml
[triggers]
crons = ["0 * * * *"] # mỗi giờ
export default {
async scheduled(event: ScheduledEvent, env: Env): Promise<void> {
await syncDataFromExternalApi(env);
},
};
Pages Functions không có cron trigger.
Queue consumer
Xử lý job từ Cloudflare Queues:
export default {
async queue(batch: MessageBatch<Job>, env: Env): Promise<void> {
for (const msg of batch.messages) {
await processJob(msg.body, env);
msg.ack();
}
},
};
Pages là gì và làm được gì
Pages là nền tảng hosting tĩnh của Cloudflare. Bạn connect repo GitHub/GitLab, mỗi lần push code Pages sẽ tự build và deploy lên CDN toàn cầu.
Điểm đặc biệt: Pages không chỉ serve file HTML/CSS/JS tĩnh — nó có Pages Functions, cho phép bạn viết server-side logic nằm ngay trong project, bind vào KV/D1/R2/Queue y hệt Workers.
Cấu trúc project Pages với Functions
my-app/
├── src/ # frontend code (Next.js, Astro,...)
├── functions/ # Pages Functions
│ ├── api/
│ │ ├── posts.ts # → /api/posts
│ │ └── contact.ts # → /api/contact
│ └── _middleware.ts # chạy trước mọi request
└── package.json
Pages Function tự routing theo tên file — không cần config thêm.
Pages phù hợp cho bài toán nào
Full-stack app với framework
Pages hỗ trợ sẵn Next.js, Astro, SvelteKit, Remix, Nuxt và nhiều framework khác qua adapter. Build một lần, Pages tự lo deploy và CDN:
# Next.js trên Pages
npm install @cloudflare/next-on-pages
# deploy
wrangler pages deploy .vercel/output/static
Static site / blog
Blog tĩnh dùng Astro, Hugo, Eleventy... — Pages serve file nhanh từ edge, không cần server:
# Astro build rồi deploy
npm run build
wrangler pages deploy dist
App có frontend + server nhẹ
SPA cần vài endpoint — viết Pages Functions thay vì dựng Workers riêng:
// functions/api/products.ts
export async function onRequestGet(context: EventContext<Env, string, unknown>) {
const products = await context.env.DB.prepare("SELECT * FROM products").all();
return Response.json(products.results);
}
Preview deployment theo branch
Mỗi PR tự động tạo URL preview riêng — tiện để review trước khi merge:
https://feat-new-checkout.my-app.pages.dev
Workers không có tính năng này.
Pages Functions chính là Workers
Điều hay bị nhầm: người ta nghĩ Pages Functions "kém hơn" Workers. Thực ra Pages Functions chạy trên cùng runtime với Workers — V8 isolates, edge network, khả năng bind KV/D1/R2/Queue y hệt nhau.
Điểm khác biệt:
- Pages Functions routing theo file system (
functions/api/users.ts→/api/users) - Workers routing do bạn tự xử lý trong code
- Pages Functions không có cron trigger
- Pages Functions không nhận Queue message trực tiếp
Nếu app của bạn là Next.js on Pages, toàn bộ API routes (app/api/) đều chạy trên Workers runtime — bạn vẫn bind được D1, KV, R2 bình thường qua process.env hoặc context.env.
Khi nào dùng Workers, khi nào dùng Pages
Dùng Workers khi
- Bạn xây API backend thuần, không có frontend đi kèm
- Cần cron trigger chạy định kỳ
- Cần nhận và xử lý message từ Queue
- Viết proxy hoặc middleware chặn trước origin
- Muốn kiểm soát hoàn toàn routing và logic không ràng buộc vào structure của Pages
- Script nhỏ chạy edge: image resize, auth check, geo redirect
Dùng Pages khi
- Có frontend framework cần deploy: Next.js, Astro, SvelteKit, Remix
- Cần static hosting + CDN cho HTML/CSS/JS/image
- Muốn preview deployment theo branch/PR
- API đơn giản, có thể đặt trong
functions/cùng project - Muốn deploy bằng git push thay vì CI/CD riêng
Dùng cả hai khi
Đây là pattern phổ biến nhất với app thật:
Pages (frontend Next.js)
└── bind KV, D1, R2
Workers (backend API riêng)
└── bind cùng KV, D1, R2
└── có cron trigger
└── nhận Queue message
Frontend gọi Worker API qua fetch("/api/...") hoặc domain riêng. Cả hai đều bind vào cùng namespace KV và database D1.
Free tier so sánh
Workers free tier
- 100.000 requests/ngày — qua giới hạn này sẽ tính phí ($0.50/triệu requests)
- 10ms CPU time/request trên free plan (không phải wall time — là thời gian CPU thực)
- Cron trigger: 1 cron/Worker trên free plan
- Không giới hạn số Worker
Pages free tier
- Không giới hạn requests — serving file tĩnh hoàn toàn miễn phí
- 500 builds/tháng (đủ dùng cho team nhỏ)
- 1 project trên free plan (paid thì unlimited)
- Preview deployment: không giới hạn
- Pages Functions dùng chung quota với Workers — vẫn tính 100.000 requests/ngày
Tức là nếu app của bạn chỉ là static site không có Functions, Pages free tier thực sự không giới hạn. Ngay khi bạn bắt đầu dùng Functions, quota sẽ tính vào Workers limit.
Tóm lại nên chọn gì
| Bạn đang làm | Nên dùng |
|---|---|
| API backend không có frontend | Workers |
| Background job, cron, Queue consumer | Workers |
| Proxy / edge middleware | Workers |
| Blog, docs site, landing page | Pages |
| Next.js / Astro / SvelteKit app | Pages |
| Full-stack với frontend + API nhẹ | Pages (+ Functions) |
| Frontend phức tạp + backend nặng | Pages + Workers riêng |
Nếu đang phân vân, quy tắc đơn giản: có frontend thì dùng Pages, không có frontend thì dùng Workers. Pages Functions đủ mạnh cho phần lớn backend nhẹ, và nếu sau này cần tách ra, chuyển Function sang Workers standalone không khó.