.do
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 →