Architecture
Scalability
Scale from 1 to 1M users seamlessly
Business-as-Code applications scale automatically from 1 to 1,000,000+ users.
Built-in Scalability
The platform provides automatic scaling through:
- Global Distribution: Cloudflare's 300+ edge locations
- Automatic Scaling: Workers scale to zero and to millions
- Event-Driven: Async processing handles load spikes
- Stateless Design: Horizontal scaling without coordination
Scaling Strategies
1. Horizontal Scaling
Application servers scale automatically:
// Stateless handlers scale horizontally
on($.Order.created, async (order) => {
// No server state, scales infinitely
await processOrder(order)
})2. Database Scaling
Read Replicas
// Read from replicas
const products = await db.read.list($.Product, query)
// Write to primary
await db.write.create($.Product, data)Sharding
// Shard by customer
const shard = hash(customer.$id) % NUM_SHARDS
const db = getShardedDB(shard)
await db.create($.Order, order)3. Caching Layers
Memory Cache
// L1: In-memory (fastest)
const memoryCache = new Map()
async function getProduct(id: string) {
if (memoryCache.has(id)) {
return memoryCache.get(id)
}
const product = await db.get($.Product, id)
memoryCache.set(id, product)
return product
}Distributed Cache
// L2: Redis/KV (fast, shared)
async function getProduct(id: string) {
const cached = await kv.get(`product:${id}`)
if (cached) return JSON.parse(cached)
const product = await db.get($.Product, id)
await kv.put(`product:${id}`, JSON.stringify(product), {
expirationTtl: 3600,
})
return product
}CDN Cache
// L3: Edge cache (fastest for static content)
export default {
async fetch(request, env, ctx) {
const cache = caches.default
const response = await cache.match(request)
if (response) return response
const newResponse = await generateResponse(request)
ctx.waitUntil(cache.put(request, newResponse.clone()))
return newResponse
},
}4. Async Processing
Event Queue
// Offload heavy work to queues
on($.Order.created, async (order) => {
// Quick acknowledgment
await db.update($.Order, order.$id, { status: 'queued' })
// Queue for processing
await queue.send('order-processing', order)
return { status: 'accepted' }
})
// Process async
consumer.on('order-processing', async (order) => {
await processOrderHeavyWork(order)
})Background Jobs
// Schedule background tasks
cron.schedule('0 * * * *', async () => {
// Hourly pricing updates
await updateAllPricing()
})5. Rate Limiting
// Per-user rate limiting
const limiter = {
async check(userId: string, limit: number) {
const key = `ratelimit:${userId}`
const current = await kv.get(key)
if (current && parseInt(current) >= limit) {
return false
}
await kv.put(key, String(parseInt(current || '0') + 1), {
expirationTtl: 60,
})
return true
},
}
app.use(async (c, next) => {
const allowed = await limiter.check(c.get('userId'), 100)
if (!allowed) {
return c.json({ error: 'Rate limit exceeded' }, 429)
}
await next()
})Performance Optimization
1. Database Optimization
Indexes
-- Add indexes for common queries
CREATE INDEX idx_orders_customer ON orders(customer_id);
CREATE INDEX idx_orders_date ON orders(order_date);
CREATE INDEX idx_products_category ON products(category);Query Optimization
// Bad: N+1 queries
const orders = await db.list($.Order)
for (const order of orders) {
order.customer = await db.get($.Person, order.customer.$id)
}
// Good: Batch fetch
const orders = await db.list($.Order)
const customerIds = orders.map((o) => o.customer.$id)
const customers = await db.getMany($.Person, customerIds)
const customerMap = new Map(customers.map((c) => [c.$id, c]))
orders.forEach((o) => (o.customer = customerMap.get(o.customer.$id)))2. Code Optimization
Lazy Loading
// Load data only when needed
class Product {
private _manufacturer?: Organization
async getManufacturer() {
if (!this._manufacturer) {
this._manufacturer = await db.get($.Organization, this.manufacturerId)
}
return this._manufacturer
}
}Memoization
// Cache expensive computations
const memoize = (fn) => {
const cache = new Map()
return (...args) => {
const key = JSON.stringify(args)
if (cache.has(key)) return cache.get(key)
const result = fn(...args)
cache.set(key, result)
return result
}
}
const expensiveCalculation = memoize((x, y) => {
// Heavy computation
return result
})3. Network Optimization
Connection Pooling
// Reuse database connections
const pool = createPool({
max: 10,
min: 2,
idleTimeoutMillis: 30000,
})
const client = await pool.connect()
try {
await client.query(sql)
} finally {
client.release()
}Request Batching
// Batch multiple requests
const batcher = new DataLoader(async (ids) => {
return await db.getMany($.Product, ids)
})
// Individual requests get batched
const [p1, p2, p3] = await Promise.all([batcher.load(id1), batcher.load(id2), batcher.load(id3)])Load Testing
Performance Benchmarks
// Load test with autocannon
import autocannon from 'autocannon'
const result = await autocannon({
url: 'https://api.yourbusiness.com',
connections: 100,
duration: 60,
requests: [
{
method: 'POST',
path: '/orders',
body: JSON.stringify(testOrder),
},
],
})
console.log({
requests: result.requests.total,
throughput: result.throughput.mean,
latency: {
p50: result.latency.p50,
p95: result.latency.p95,
p99: result.latency.p99,
},
})Monitoring at Scale
Metrics
// Track key performance metrics
const metrics = {
requestRate: histogram('request_duration_seconds'),
errorRate: counter('errors_total'),
activeUsers: gauge('active_users'),
cacheHitRate: gauge('cache_hit_rate'),
}
// Record metrics
metrics.requestRate.observe(duration)
metrics.errorRate.inc({ type: 'validation' })Alerting
// Alert on performance degradation
if (metrics.p95Latency > 1000) {
await alert.send({
severity: 'warning',
message: 'P95 latency > 1s',
value: metrics.p95Latency,
})
}
if (metrics.errorRate > 0.01) {
await alert.send({
severity: 'critical',
message: 'Error rate > 1%',
value: metrics.errorRate,
})
}Scaling Checklist
- Stateless application design
- Database indexes on common queries
- Multi-layer caching strategy
- Async processing for heavy work
- Rate limiting per user/IP
- CDN for static assets
- Connection pooling
- Request batching
- Load testing
- Performance monitoring
- Auto-scaling configured
- Circuit breakers for external services
Summary
Business-as-Code applications scale through:
- Automatic Scaling: Workers scale on demand
- Global Distribution: 300+ edge locations
- Smart Caching: Multi-layer cache strategy
- Async Processing: Queue heavy operations
- Optimization: Database, code, network
- Monitoring: Track and alert on metrics
Start small, measure continuously, optimize bottlenecks.
Back to: Architecture →