
Cloudflare chính thức ra mắt Workers Cache: một bộ nhớ đệm phân tầng (tiered cache) nằm ngay phía trước Worker của bạn. Để kích hoạt nó, bạn chỉ cần thêm đúng một dòng vào file cấu hình Wrangler và sử dụng các HTTP header Cache-Control quen thuộc.
Khi Workers Cache được bật, mọi request có thể cache được gửi tới Worker sẽ đi qua bộ nhớ đệm của Cloudflare trước. Nếu có sẵn dữ liệu mới trong cache, Cloudflare sẽ trả về ngay lập tức — Worker của bạn không hề chạy, và bạn không phải trả tiền cho thời gian CPU đó. Nếu không có trong cache (miss), Worker sẽ chạy và nếu phản hồi của bạn có thể cache được, Cloudflare sẽ lưu nó lại cho các yêu cầu tiếp theo. Request tiếp theo từ bất kỳ đâu trên thế giới sẽ được phục vụ thẳng từ bộ nhớ đệm.
Để kích hoạt tính năng này, tất cả những gì bạn cần là một khối cấu hình trong file wrangler.toml :
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2026-05-01",
"cache": {
"enabled": true
}
}
Sau đó, bạn kiểm soát việc caching theo cách chuẩn xác của HTTP — bằng cách thiết lập các header trên phản hồi của bạn:
return new Response(body, {
headers: {
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
"Cache-Tag": "products,product:123",
},
});
Và khi nội dung thay đổi, Worker của bạn có thể tự xóa bộ nhớ đệm của chính nó một cách dễ dàng:
await ctx.cache.purge({ tags: ["product:123"] });
Đó là toàn bộ API! Không cần cấu hình ở cấp độ Zone, không cần thiết lập rules engine (công cụ quy tắc), không cần cấp phát cache riêng biệt, và không có sản phẩm phụ nào để đăng nhập. Bản thân code của Worker chính là nơi cấu hình, và bộ nhớ đệm này sẽ theo Worker tới bất cứ đâu nó chạy — trên custom domain, trên workers.dev, hay trong môi trường preview. Một Worker, một bộ nhớ đệm, cấu hình một lần duy nhất.
Tại sao các ứng dụng Server-Rendered (SSR) lại cần một bộ nhớ đệm ở phía trước?
Khi Cloudflare giới thiệu Workers vào năm 2017, định hướng lúc bấy giờ là chạy code trên mạng lưới Cloudflare để biến đổi các request trước khi chúng đến server gốc (origin) của bạn. Worker đứng giữa bộ nhớ đệm và server gốc. Đó là một mô hình tuyệt vời để rewrite URL, A/B testing, hoặc thêm header.
Nhưng thế giới đã thay đổi. Worker không còn là thứ được đính kèm vào server gốc nữa, mà Worker đã trở thành server gốc. Các framework như Astro, Next.js, Remix, hay SvelteKit đều build ứng dụng của bạn thành một Worker.
Khi Worker là server gốc, kiến trúc cũ không có gì để cache cả. Mỗi request đều phải chạy code của bạn. Dù runtime của Workers cực kỳ nhanh, nhưng việc "render mọi request" vẫn tiêu tốn độ trễ (latency) của người dùng và CPU của bạn.
Workers Cache lật ngược lại kiến trúc này. Giờ đây, bộ nhớ đệm của Cloudflare sẽ nằm phía trước Worker:
Với Workers Cache, bạn có thêm một lựa chọn thứ ba hoàn hảo cho SSR: server-render theo yêu cầu, cache lại phản hồi đã render, và tự động làm mới nó. Tốc độ của một trang tĩnh (static site) mà không cần mất thời gian build, cộng với sự mới mẻ của server-rendering mà không tốn kém chi phí.
stale-while-revalidate - Chìa khóa mang lại cảm giác phản hồi "tức thì"
Chỉ thị stale-while-revalidate nói với Cloudflare rằng khi một phản hồi trong cache hết hạn, nó được phép phục vụ bản sao cũ ngay lập tức, trong khi âm thầm chạy nền (background) để làm mới dữ liệu.
Nếu không có nó, người dùng gửi request đầu tiên sau khi cache hết hạn sẽ phải đợi Worker render lại trang. Với nó, người dùng nhận ngay bản cũ, và Worker chạy ngầm để nạp lại cache. Code trông sẽ như thế này:
export default {
async fetch(request) {
const html = await renderPage(request);
return new Response(html, {
headers: {
"Content-Type": "text/html; charset=utf-8",
// Xem là "tươi mới" trong 5 phút; phục vụ bản cũ (stale) lên tới 1 giờ
// trong khi tiến trình background chạy làm mới dữ liệu.
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
},
});
},
};
Một URL, nhiều định dạng: Hỗ trợ hoàn hảo cho Vary
Các ứng dụng thực tế hiếm khi trả về cùng một lượng byte cho mọi client. Ví dụ, ảnh WebP cho trình duyệt hỗ trợ nó và JPEG cho những trình duyệt không hỗ trợ.
Workers Cache hỗ trợ chuẩn HTTP Vary. Khi Worker trả về header Vary: Accept, Cloudflare sẽ lưu các bản sao riêng biệt trong cache dựa trên các giá trị header tương ứng:
export default {
async fetch(request) {
const accept = request.headers.get("Accept") ?? "";
const wantsWebp = accept.includes("image/webp");
const body = wantsWebp ? await fetchWebpImage() : await fetchJpegImage();
return new Response(body, {
headers: {
"Content-Type": wantsWebp ? "image/webp" : "image/jpeg",
"Cache-Control": "public, max-age=3600",
// Cache một phiên bản riêng biệt cho mỗi giá trị Accept header khác nhau.
Vary: "Accept",
},
});
},
};
Khả năng cấu hình Caching theo từng Entrypoint (Điểm chạm)
Sức mạnh thực sự của Workers Cache nằm ở chỗ bạn có thể thiết lập cấu hình trên mỗi entrypoint. Bạn có thể xây dựng Worker thành một chuỗi các entrypoint nhỏ — xác thực (auth), chuẩn hóa, routing, đọc database — và nhét Workers Cache vào bất cứ đâu bạn muốn.
Dưới đây là một cấu hình wrangler.json (hoặc toml) nơi entrypoint chính không được cache (để chạy auth), nhưng phần backend đắt đỏ thì được cache:
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2026-05-01",
"cache": {
"enabled": true
},
"exports": {
// Gateway chạy với mọi request — đừng cache nó.
"default": {
"type": "worker",
"cache": {
"enabled": false
}
},
// Cache entrypoint bên trong vì xử lý rất tốn kém.
"CachedBackend": {
"type": "worker",
"cache": {
"enabled": true
}
}
}
}
Và phần code tương ứng để hiện thực hóa kiến trúc này:
import { WorkerEntrypoint } from "cloudflare:workers";
interface Env {
API_TOKEN: string;
}
interface Props {
userId: string;
}
// Inner entrypoint: phần việc tốn kém. Workers Cache nằm phía trước nó
// nếu có hit cache, phần code này sẽ không bao giờ chạy.
export class CachedBackend extends WorkerEntrypoint<Env, Props> {
async fetch(request: Request): Promise<Response> {
// ctx.props.userId là một phần của cache key, do đó nó được cache
// tách biệt cho từng user.
const { userId } = this.ctx.props;
const data = await loadExpensiveData(userId);
return new Response(JSON.stringify(data), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
"Cache-Tag": `user:${userId}`,
},
});
}
// Xóa cache của một user. purge() có phạm vi (scoped) với entrypoint
// gọi nó, vì vậy nó phải chạy bên trong CachedBackend — entrypoint sở hữu phản hồi đã cache.
async invalidate(userId: string): Promise<void> {
await this.ctx.cache.purge({ tags: [`user:${userId}`] });
}
}
(Lưu ý: Entrypoint bên ngoài (outer entrypoint) sẽ chạy để xác thực, và gọi tới CachedBackend thông qua ctx.exports)
Hỗ trợ First-Class trên Framework của bạn
Nếu bạn đang sử dụng Astro, Cloudflare adapter đã tích hợp sẵn Workers Cache. Bạn chỉ cần thêm provider cacheCloudflare vào cấu hình là xong:
// astro.config.mjs
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
import { cacheCloudflare } from "@astrojs/cloudflare/cache";
export default defineConfig({
adapter: cloudflare(),
output: "server",
experimental: {
cache: {
provider: cacheCloudflare()
},
routeRules: {
"/products/*": {
maxAge: 300,
swr: 3600,
tags: ["products"]
},
"/blog/*": {
maxAge: 60,
swr: 86400,
tags: ["blog"]
},
},
},
});
Chỉ với cấu hình này, Astro sẽ tự động gắn đúng các header, tag vào response, và cung cấp hàm cache.invalidate() để bạn purge cache khi có nội dung mới.
Workers Cache mang tới một luồng gió mới, loại bỏ hoàn toàn những phức tạp trước đây của việc cấu hình cache hệ thống CDN và đưa sức mạnh đó vào tay lập trình viên bằng chính những dòng code quen thuộc.