Cloudflare Developer Platform — Xây Full-Stack App Miễn Phí trên Edge
Posted on: 4/20/2026 12:09:41 PM
Table of contents
- 1. Tổng quan Cloudflare Developer Platform
- 2. Kiến trúc V8 Isolates — Vì sao Workers nhanh đến vậy?
- 3. D1 — SQLite Database trên Edge
- 4. R2 — Object Storage không tốn Egress Fee
- 5. KV — Key-Value Store cho Read-Heavy Workloads
- 6. Hono — Framework tối ưu cho Workers
- 7. Kiến trúc Full-Stack trên Cloudflare
- 8. Free Tier chi tiết — Được bao nhiêu?
- 9. Deploy thực tế: Từ zero đến production
- 10. Best Practices và những bẫy cần tránh
- 11. So sánh với đối thủ: Vercel, Netlify, AWS
- 12. Drizzle ORM — Type-safe queries cho D1
- 13. Monitoring và Observability
- 14. Khi nào nên rời Cloudflare?
- Tổng kết
1. Tổng quan Cloudflare Developer Platform
Trong thế giới cloud, ba ông lớn AWS, Azure, GCP thường được nhắc đến đầu tiên. Nhưng nếu bạn là một indie developer, startup nhỏ, hoặc team muốn ship nhanh mà không lo chi phí ban đầu, có một lựa chọn đáng ngạc nhiên: Cloudflare Developer Platform. Không chỉ là một CDN hay DNS provider, Cloudflare đã âm thầm xây dựng một hệ sinh thái compute + storage + database hoàn chỉnh — và miễn phí ở mức đủ dùng cho production nhỏ.
Điểm khác biệt cốt lõi: thay vì chạy code trong data center tập trung (us-east-1, westeurope...), toàn bộ stack của Cloudflare chạy trên 300+ edge locations — code của bạn literally thực thi cách người dùng chỉ vài millisecond. Đây không phải CDN cache tĩnh, mà là full compute tại edge.
2. Kiến trúc V8 Isolates — Vì sao Workers nhanh đến vậy?
2.1. Containers vs V8 Isolates
AWS Lambda và Azure Functions chạy code trong container: mỗi request cần một container riêng (hoặc warm container), mỗi container tiêu tốn hàng chục MB RAM và mất 100–1000ms để cold start. Cloudflare Workers đi một con đường hoàn toàn khác: sử dụng V8 Isolates — cùng engine V8 mà Chrome/Node.js dùng, nhưng thay vì spawn cả một process, Workers tạo một isolate nhẹ trong cùng một process.
Một isolate tiêu tốn khoảng 5MB overhead so với 50–300MB của container. Cold start dưới 1ms so với 100–1000ms. Điều này cho phép Cloudflare chạy hàng nghìn Workers trên cùng một máy, từ đó deploy trên 300+ locations mà chi phí vẫn kiểm soát được.
graph LR
subgraph Traditional["Lambda / Azure Functions"]
C1[Container 1
~100MB RAM
Cold: 100-1000ms]
C2[Container 2
~100MB RAM]
C3[Container 3
~100MB RAM]
end
subgraph Edge["Cloudflare Workers"]
P[Shared V8 Process]
I1[Isolate 1
~5MB]
I2[Isolate 2
~5MB]
I3[Isolate 3
~5MB]
I4[Isolate N
~5MB]
P --> I1
P --> I2
P --> I3
P --> I4
end
style C1 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style C2 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style C3 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style P fill:#e94560,stroke:#fff,color:#fff
style I1 fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style I2 fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style I3 fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
style I4 fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
So sánh mô hình Container (Lambda) vs V8 Isolates (Workers)
2.2. Execution Model
Workers sử dụng mô hình event-driven dựa trên Fetch API chuẩn Web. Mỗi request là một FetchEvent, handler trả về một Response. Không có Express, không có middleware chain phức tạp — chỉ là Web Standards thuần túy:
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
if (url.pathname === '/api/users') {
const users = await env.DB.prepare(
'SELECT * FROM users LIMIT 10'
).all();
return Response.json(users.results);
}
return new Response('Not Found', { status: 404 });
}
};
env chứa tất cả bindings — kết nối tới D1, R2, KV, Durable Objects. Không cần connection string, không cần SDK riêng. Cloudflare tự inject qua runtime.
Tip: Workers hỗ trợ cả Node.js API
Từ 2024, Workers đã bật nodejs_compat compatibility flag, cho phép sử dụng nhiều Node.js built-in modules như crypto, buffer, stream, util. Đa số npm package phổ biến đã tương thích.
3. D1 — SQLite Database trên Edge
3.1. SQLite nhưng distributed
D1 là cơ sở dữ liệu SQL serverless của Cloudflare, được xây dựng trên SQLite. Nghe có vẻ đơn giản, nhưng D1 giải quyết được vấn đề lớn nhất của SQLite truyền thống: single-writer, single-machine.
D1 có một primary instance (nhận writes) và tự động tạo read replicas tại các edge locations gần người dùng. Khi bạn query read-only, request được route tới replica gần nhất — latency đọc có thể dưới 1ms. Writes vẫn phải đi về primary, nhưng với cơ chế Session API, bạn có thể đảm bảo read-after-write consistency khi cần.
| Tiêu chí | D1 (Cloudflare) | PostgreSQL (Neon/Supabase) | PlanetScale (MySQL) |
|---|---|---|---|
| Engine | SQLite | PostgreSQL | Vitess (MySQL) |
| Read latency (p50) | ~0.5ms | 1–3ms (same region) | 3–10ms |
| Write throughput | 500–2K ops/s | 10K–50K ops/s | 10K+ ops/s |
| Free tier storage | 5 GB | 512 MB (Neon) | 5 GB |
| Free reads/tháng | 5 tỷ row reads | 3 GB transfer | 1 tỷ row reads |
| Global replicas | Tự động (edge) | Manual (pay extra) | Có (paid) |
| Backup / Recovery | Time Travel 30 ngày | Point-in-time 7 ngày | Branching |
| ORM support | Drizzle, Prisma | Mọi ORM | Prisma, Drizzle |
3.2. Khi nào NÊN và KHÔNG NÊN dùng D1
D1 phù hợp với:
Blog, landing page, SaaS nhỏ–vừa, API backend có read-heavy workload, side projects, MVP. Bất cứ app nào mà tổng data dưới 10 GB và write không quá 2K ops/s.
D1 KHÔNG phù hợp với:
Ứng dụng write-heavy (e-commerce lớn, real-time chat), data warehouse, hoặc hệ thống cần strong consistency toàn cầu tức thì. Với những trường hợp này, hãy xem xét PostgreSQL (Neon) hoặc CockroachDB.
3.3. Ví dụ thực tế: CRUD với D1
// wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "my-app-db"
database_id = "xxxx-xxxx-xxxx"
// Schema migration
// wrangler d1 execute my-app-db --file=./schema.sql
-- schema.sql
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_posts_slug ON posts(slug);
CREATE INDEX idx_posts_created ON posts(created_at DESC);
// Worker handler
async function handleGetPost(slug, env) {
const post = await env.DB.prepare(
'SELECT * FROM posts WHERE slug = ?'
).bind(slug).first();
if (!post) {
return new Response('Not found', { status: 404 });
}
return Response.json(post, {
headers: { 'Cache-Control': 'public, max-age=3600' }
});
}
async function handleCreatePost(request, env) {
const { title, content, slug } = await request.json();
const result = await env.DB.prepare(
'INSERT INTO posts (title, content, slug) VALUES (?, ?, ?)'
).bind(title, content, slug).run();
return Response.json(
{ id: result.meta.last_row_id },
{ status: 201 }
);
}
4. R2 — Object Storage không tốn Egress Fee
4.1. Giá trị cốt lõi: Zero egress
Nếu bạn từng dùng AWS S3, bạn biết nỗi đau: egress fee. Upload miễn phí, nhưng mỗi GB data người dùng download, AWS tính $0.09. Một website có 1 TB bandwidth/tháng? Đó là $90 chỉ riêng egress.
R2 giải quyết triệt để: zero egress fee, mãi mãi. Bạn chỉ trả storage ($0.015/GB/tháng) và operations (Class A: $4.50/triệu, Class B: $0.36/triệu). Free tier bao gồm:
4.2. S3-Compatible API
R2 tương thích hoàn toàn với S3 API. Mọi tool, SDK, library mà bạn đang dùng với S3 đều hoạt động với R2 — chỉ cần đổi endpoint. AWS SDK, boto3, rclone, Cyberduck... tất cả đều compatible.
// Upload file từ Worker
async function handleUpload(request, env) {
const formData = await request.formData();
const file = formData.get('file');
const key = `uploads/${Date.now()}-${file.name}`;
await env.R2_BUCKET.put(key, file.stream(), {
httpMetadata: {
contentType: file.type,
},
customMetadata: {
uploadedBy: 'api',
},
});
return Response.json({ key, url: `/files/${key}` });
}
// Serve file với caching
async function handleDownload(key, env) {
const object = await env.R2_BUCKET.get(key);
if (!object) {
return new Response('Not found', { status: 404 });
}
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set('etag', object.httpEtag);
headers.set('Cache-Control', 'public, max-age=86400');
return new Response(object.body, { headers });
}
4.3. Infrequent Access class (2026)
Năm 2026, R2 bổ sung Infrequent Access (IA) storage class: $0.01/GB/tháng (rẻ hơn 33% so với Standard). Phù hợp cho backup, archive, log storage. Tuy nhiên, IA có retrieval fee cao hơn — chỉ dùng cho data ít truy cập.
5. KV — Key-Value Store cho Read-Heavy Workloads
Workers KV là một eventually consistent, global key-value store. Data được replicate tới tất cả edge locations, cho phép reads cực nhanh (<10ms globally). Trade-off: writes mất tới 60 giây để propagate toàn cầu.
| Tiêu chí | KV | D1 | Durable Objects |
|---|---|---|---|
| Mô hình | Key-Value | Relational (SQL) | Actor model |
| Consistency | Eventually (~60s) | Session-based | Strong |
| Read latency | <10ms global | ~0.5ms (replica) | ~20ms |
| Use case | Config, cache, feature flags | CRUD, queries | Collaboration, counters |
| Free tier | 100K reads/ngày | 5 tỷ reads/tháng | Không có free |
| Max value size | 25 MB | N/A (row-based) | 128 KB/key |
// Config store pattern với KV
async function getFeatureFlags(env) {
let flags = await env.KV.get('feature-flags', { type: 'json' });
if (!flags) {
// Fallback: đọc từ D1
const result = await env.DB.prepare(
'SELECT key, value FROM feature_flags WHERE active = 1'
).all();
flags = Object.fromEntries(
result.results.map(r => [r.key, JSON.parse(r.value)])
);
// Cache vào KV (TTL 5 phút)
await env.KV.put('feature-flags', JSON.stringify(flags), {
expirationTtl: 300
});
}
return flags;
}
6. Hono — Framework tối ưu cho Workers
6.1. Vì sao không dùng Express?
Express được thiết kế cho Node.js — nó phụ thuộc vào http.createServer, req/res objects, và Node.js stream. Workers không chạy Node.js mà chạy trên V8 Isolates với Web Standards (Fetch API). Hono là framework được thiết kế từ đầu cho edge runtimes:
6.2. Full-stack API với Hono + D1 + R2
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { cache } from 'hono/cache';
import { jwt } from 'hono/jwt';
type Bindings = {
DB: D1Database;
R2_BUCKET: R2Bucket;
KV: KVNamespace;
JWT_SECRET: string;
};
const app = new Hono<{ Bindings: Bindings }>();
// Middleware
app.use('/api/*', cors());
app.use('/api/admin/*', jwt({ secret: 'JWT_SECRET' }));
// Cache static assets
app.get('/files/*',
cache({ cacheName: 'assets', cacheControl: 'max-age=86400' })
);
// Posts CRUD
app.get('/api/posts', async (c) => {
const page = Number(c.req.query('page') || 1);
const limit = 20;
const offset = (page - 1) * limit;
const { results, meta } = await c.env.DB.prepare(`
SELECT id, title, slug, created_at
FROM posts
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`).bind(limit, offset).all();
return c.json({ posts: results, meta });
});
app.get('/api/posts/:slug', async (c) => {
const slug = c.req.param('slug');
const post = await c.env.DB.prepare(
'SELECT * FROM posts WHERE slug = ?'
).bind(slug).first();
if (!post) return c.notFound();
return c.json(post);
});
app.post('/api/posts', async (c) => {
const { title, content, slug } = await c.req.json();
const result = await c.env.DB.prepare(`
INSERT INTO posts (title, content, slug) VALUES (?, ?, ?)
`).bind(title, content, slug).run();
return c.json({ id: result.meta.last_row_id }, 201);
});
// File upload
app.post('/api/upload', async (c) => {
const body = await c.req.parseBody();
const file = body['file'] as File;
const key = `uploads/${crypto.randomUUID()}-${file.name}`;
await c.env.R2_BUCKET.put(key, file.stream(), {
httpMetadata: { contentType: file.type },
});
return c.json({ key });
});
export default app;
Tại sao Hono thắng Express trên Edge?
Hono dùng Fetch API gốc (Request/Response) thay vì Node.js http module. Bundle size chỉ 14KB vs Express 200KB+. Router dùng Trie-based algorithm, benchmark cho thấy routing nhanh hơn Express 4x. Quan trọng nhất: Hono chạy trên mọi runtime — viết 1 lần, deploy khắp nơi (Workers, Deno, Bun, Lambda).
7. Kiến trúc Full-Stack trên Cloudflare
graph TB
User((User)) -->|HTTPS| CF[Cloudflare Edge
300+ PoP]
CF -->|Static files| Pages[Pages
Vue/React SPA]
CF -->|/api/*| Worker[Worker
Hono API]
Worker -->|SQL queries| D1[(D1 Database
SQLite)]
Worker -->|File storage| R2[(R2 Bucket
S3-compatible)]
Worker -->|Cache/Config| KV[(KV Store
Global cache)]
Worker -->|Real-time| DO[Durable Objects
WebSocket]
D1 -.->|Read replicas| Edge2[Edge Replica]
KV -.->|Replicated| Edge3[All 300+ PoP]
style User fill:#e94560,stroke:#fff,color:#fff
style CF fill:#2c3e50,stroke:#fff,color:#fff
style Pages fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style Worker fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style D1 fill:#16213e,stroke:#fff,color:#fff
style R2 fill:#16213e,stroke:#fff,color:#fff
style KV fill:#16213e,stroke:#fff,color:#fff
style DO fill:#16213e,stroke:#fff,color:#fff
style Edge2 fill:#4CAF50,stroke:#fff,color:#fff
style Edge3 fill:#4CAF50,stroke:#fff,color:#fff
Kiến trúc full-stack application trên Cloudflare Developer Platform
7.1. Cấu trúc project khuyến nghị
my-app/
├── src/
│ ├── index.ts # Hono app entry
│ ├── routes/
│ │ ├── posts.ts # /api/posts
│ │ ├── auth.ts # /api/auth
│ │ └── upload.ts # /api/upload
│ ├── middleware/
│ │ ├── auth.ts # JWT verification
│ │ └── rateLimit.ts # Rate limiting via KV
│ └── lib/
│ ├── db.ts # D1 query helpers
│ └── storage.ts # R2 operations
├── frontend/ # Vue/React SPA
│ ├── src/
│ └── dist/ # Build output → Pages
├── migrations/
│ ├── 0001_init.sql
│ └── 0002_add_tags.sql
├── wrangler.toml # Bindings config
└── package.json
7.2. Wrangler config — kết nối mọi thứ
# wrangler.toml
name = "my-app"
main = "src/index.ts"
compatibility_date = "2026-04-01"
compatibility_flags = ["nodejs_compat"]
# Static assets (thay Pages)
[assets]
directory = "./frontend/dist"
# D1 Database
[[d1_databases]]
binding = "DB"
database_name = "my-app-db"
database_id = "your-d1-id"
# R2 Bucket
[[r2_buckets]]
binding = "R2_BUCKET"
bucket_name = "my-app-files"
# KV Namespace
[[kv_namespaces]]
binding = "KV"
id = "your-kv-id"
# Environment variables
[vars]
ENVIRONMENT = "production"
# Secrets (set via `wrangler secret put`)
# JWT_SECRET, API_KEY, etc.
8. Free Tier chi tiết — Được bao nhiêu?
| Service | Free Tier | Paid (Workers Paid $5/tháng) |
|---|---|---|
| Workers | 100K requests/ngày, 10ms CPU/request | 10M requests/tháng, 30s CPU/request |
| D1 | 5 GB storage, 5B reads, 100K writes/ngày | 5 GB free + $0.75/GB, 25B reads, 50M writes |
| R2 | 10 GB storage, 1M Class A, 10M Class B | $0.015/GB/tháng, zero egress |
| KV | 100K reads/ngày, 1K writes/ngày | 10M reads, 1M writes/tháng |
| Pages | 500 builds/tháng, unlimited bandwidth | 5000 builds/tháng |
| Durable Objects | Không có | $0.15/triệu requests |
Con số thực tế: Free tier đủ cho bao nhiêu?
100K requests/ngày = ~3 triệu/tháng. Một blog cá nhân trung bình có 10K–50K pageviews/tháng. Một SaaS nhỏ với 500 DAU, mỗi user 20 API calls/ngày = 10K requests/ngày. Free tier thừa sức cho giai đoạn 0→1 và thậm chí sống thoải mái đến vài nghìn DAU.
9. Deploy thực tế: Từ zero đến production
9.1. Setup ban đầu
# Cài Wrangler CLI
npm install -g wrangler
# Login
wrangler login
# Tạo project mới với Hono template
npm create hono@latest my-app
# Chọn: cloudflare-workers
cd my-app
# Tạo D1 database
wrangler d1 create my-app-db
# → Copy database_id vào wrangler.toml
# Tạo R2 bucket
wrangler r2 bucket create my-app-files
# Tạo KV namespace
wrangler kv namespace create KV
# → Copy id vào wrangler.toml
9.2. Migration và seed data
# Chạy migration
wrangler d1 execute my-app-db --file=./migrations/0001_init.sql
# Seed data (local)
wrangler d1 execute my-app-db --local --file=./seed.sql
# Dev server (local)
wrangler dev
# Deploy production
wrangler deploy
9.3. Custom domain
# Nếu domain đã trên Cloudflare DNS
# Workers → Settings → Domains → Add custom domain
# Hoặc trong wrangler.toml:
routes = [
{ pattern = "api.myapp.com/*", zone_name = "myapp.com" }
]
10. Best Practices và những bẫy cần tránh
10.1. Performance
- Batch D1 queries: D1 hỗ trợ
db.batch()— gộp nhiều queries vào 1 round-trip thay vì gọi tuần tự. Với 5 queries, batch nhanh hơn 3–5x. - Cache với KV hoặc Cache API: Đừng query D1 cho mỗi request giống nhau. Dùng
caches.defaulthoặc KV để cache response phổ biến. - R2 + Cache: Set
Cache-Controlheader khi serve R2 objects — Cloudflare CDN tự cache ở edge, không cần tự implement. - Bundle size: Workers giới hạn 1MB (compressed). Tránh import library lớn, dùng tree-shaking, chọn lightweight alternatives (date-fns thay moment, hono thay express).
10.2. Security
- Secrets: Dùng
wrangler secret putcho API keys, JWT secrets — KHÔNG đặt trong wrangler.toml hay code. - CORS: Hono có middleware
cors()built-in, nhưng hãy whitelist domain cụ thể thay vìorigin: '*'trong production. - Rate limiting: Cloudflare có Rate Limiting rules miễn phí (10K requests/tháng trên free plan) hoặc tự implement bằng KV/Durable Objects.
- D1 parameterized queries: Luôn dùng
.bind()— D1 API không cho phép string interpolation trực tiếp, nên SQL injection gần như bị loại bỏ bởi design.
10.3. Những giới hạn cần biết
Giới hạn quan trọng
CPU time: Free tier chỉ 10ms CPU/request (không phải wall-clock time). Các tác vụ nặng (image processing, PDF generation) sẽ timeout. D1 size: Max 10 GB/database — đủ cho hầu hết app nhỏ–vừa, nhưng nếu data growth vượt mức, cần sharding hoặc chuyển sang Postgres. Workers memory: 128 MB/isolate — không load dataset lớn vào memory. KV consistency: Writes mất tới 60s để propagate — không dùng KV cho data cần real-time sync.
11. So sánh với đối thủ: Vercel, Netlify, AWS
| Tiêu chí | Cloudflare | Vercel | Netlify | AWS (Lambda+S3+RDS) |
|---|---|---|---|---|
| Edge compute | 300+ PoP, V8 Isolates | Edge Functions (limited) | Edge Functions | Lambda@Edge (CloudFront) |
| Database | D1 (SQLite), built-in | Không có (dùng Neon/Supabase) | Không có | RDS/Aurora (không edge) |
| Object storage | R2 (zero egress) | Blob Storage ($0.03/GB) | Blobs (limited) | S3 ($0.09/GB egress) |
| Cold start | <1ms | ~50–200ms | ~100ms | 100–1000ms |
| Free tier value | Rất rộng | Tốt (hobby plan) | Tốt | 12 tháng free trial |
| Vendor lock-in | Trung bình (Hono portable) | Cao (Next.js coupling) | Thấp | Cao |
12. Drizzle ORM — Type-safe queries cho D1
Viết raw SQL cho D1 hoạt động tốt, nhưng với ứng dụng lớn hơn, Drizzle ORM là lựa chọn tốt nhất cho Workers:
// schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
content: text('content').notNull(),
slug: text('slug').unique().notNull(),
createdAt: text('created_at').default('CURRENT_TIMESTAMP'),
});
export const tags = sqliteTable('tags', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').unique().notNull(),
});
// Type-safe query
import { drizzle } from 'drizzle-orm/d1';
import { eq, desc } from 'drizzle-orm';
const db = drizzle(env.DB, { schema: { posts, tags } });
const recentPosts = await db
.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(10);
// Full type inference — IDE autocomplete cho tất cả columns
Vì sao Drizzle thắng Prisma trên Workers?
Prisma Client cần binary engine (~10MB) — quá lớn cho Workers 1MB limit. Drizzle là pure TypeScript, zero runtime dependencies, bundle ~50KB. Ngoài ra Drizzle Kit có drizzle-kit generate tạo migration SQL tương thích D1 ngay lập tức.
13. Monitoring và Observability
Cloudflare cung cấp observability cơ bản miễn phí qua Dashboard: request count, error rate, CPU time, bandwidth. Với nhu cầu nâng cao hơn:
- Workers Logpush: Stream logs realtime tới R2 bucket hoặc external service (Datadog, Grafana Cloud). Free trên Workers Paid plan.
- Tail Workers: Một Worker đặc biệt nhận events từ Workers khác — dùng để build custom logging pipeline mà không ảnh hưởng latency của Worker chính.
- Workers Analytics Engine: Write-optimized analytics database trên edge. Free tier: 100K events/ngày.
// Tail Worker pattern — async logging
export default {
async tail(events) {
for (const event of events) {
if (event.outcome === 'exception') {
// Log errors tới R2 hoặc external service
await logToR2(event);
}
}
}
};
14. Khi nào nên rời Cloudflare?
Cloudflare Developer Platform rất mạnh cho một phân khúc cụ thể. Nhưng nó không phải silver bullet:
- Write-heavy workloads: D1 giới hạn 2K writes/s. Nếu app cần 10K+ writes/s (real-time bidding, IoT telemetry), hãy xem PostgreSQL hoặc ClickHouse.
- Long-running tasks: Workers timeout sau 30s (paid) hoặc 10ms CPU (free). Background jobs nặng cần queue + consumer pattern hoặc chuyển sang traditional server.
- Large binary processing: Image/video processing tại edge bị giới hạn bởi 128MB memory. Dùng Workers AI cho inference, hoặc offload sang dedicated service.
- Complex relational queries: D1 là SQLite — không có stored procedures, triggers phức tạp, materialized views. PostgreSQL vẫn vượt trội cho enterprise-grade SQL.
Lộ trình thực tế
Bắt đầu với Cloudflare free tier cho MVP → validate product–market fit → khi cần scale writes hoặc complex queries, tách database ra Neon/Supabase (PostgreSQL) và giữ Workers + R2 cho compute + storage. Hono app portable — chuyển runtime chỉ cần đổi adapter, không rewrite code.
Tổng kết
Cloudflare Developer Platform là một trong những bí mật tốt nhất của thế giới web development. Với free tier hào phóng, kiến trúc edge-first cho latency cực thấp, và hệ sinh thái tích hợp chặt chẽ (Workers + D1 + R2 + KV), đây là nền tảng lý tưởng cho indie developers, startups, và side projects muốn ship nhanh mà không lo chi phí.
Kết hợp với Hono framework và Drizzle ORM, bạn có một full-stack type-safe, portable, hiệu năng cao — viết một lần, deploy trên 300+ edge locations, phục vụ người dùng toàn cầu với latency dưới 50ms. Và tất cả bắt đầu với $0.
Nguồn tham khảo:
Cloudflare Workers Documentation ·
Cloudflare D1 Documentation ·
Cloudflare R2 Documentation ·
Hono.js — Getting Started with Cloudflare Workers ·
Cloudflare Blog — Full-Stack Development on Workers ·
Cloudflare Blog — D1: We Turned It Up to 11 ·
Drizzle ORM — Cloudflare D1 Guide
Database Indexing — Nghệ thuật tối ưu query cho hệ thống Production
Message Queue 2026: RabbitMQ vs SQS vs Azure Service Bus Cho Production
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.