Skip to content

Cloudflare Platform Overview

Why Cloudflare, what we use, and how it maps to z0 primitives.

Prerequisites: PRINCIPLES.md, PRIMITIVES.md


z0 requires infrastructure that matches three fundamental needs:

NeedWhyCloudflare Answer
Edge-firstRouting decisions must be fast (< 50ms). Latency kills RTB auctions.Workers run in 300+ locations, code executes close to users
Globally consistent stateEntity ledgers must be authoritative. No split-brain, no eventual consistency surprises.Durable Objects provide single-threaded, strongly consistent state per entity
Serverless economicsPay for invocations, not idle capacity. Scale to zero when quiet, scale infinitely when busy.No servers to provision. Usage-based pricing across all services

The alternative: Running our own distributed database cluster, managing replication, handling failover, provisioning capacity. This is infrastructure work, not z0 work.

The tradeoff: Cloudflare is opinionated. We accept their constraints in exchange for not building distributed systems primitives ourselves.


What: Serverless JavaScript/TypeScript execution at the edge.

z0 uses for:

  • HTTP request handling (API endpoints, webhooks)
  • Routing logic evaluation
  • Orchestrating Durable Object calls
  • External tool integrations (Twilio, OpenAI)

Key properties:

  • 0ms cold start (V8 isolates, not containers)
  • 30-second CPU time limit per request
  • No persistent state (stateless by design)
  • Global deployment by default

Constraint: Workers are stateless. All state lives in Durable Objects, D1, or R2.


What: Single-threaded, globally unique objects with persistent storage.

z0 uses for:

  • Per-entity ledgers (the Fact append log)
  • Cached state (BudgetState, CapState, AccessState)
  • Config version management
  • Concurrency control (single-threaded = no race conditions)

Key properties:

  • Exactly one instance globally per ID
  • Single-threaded execution (serialized access)
  • Transactional SQLite storage (local to the DO)
  • Automatic geographic placement (moves toward callers)

Why this matters for z0:

// Entity "account_123" → Durable Object "account_123"
// All Facts for this account append to this DO's ledger
// All budget checks read from this DO's cached state
// Single-threaded = no race conditions on budget updates

Constraint: DOs are single-writer. High-throughput scenarios require sharding (see sharding-patterns.md).


What: Distributed SQLite database.

z0 uses for:

  • Cross-entity queries (“all Facts for tenant X”)
  • Reporting and analytics aggregation
  • Entity lookups by external ID
  • Historical Fact queries

Key properties:

  • SQL query interface
  • Read replicas at the edge
  • Automatic replication from primary
  • Familiar SQLite semantics

Why this matters for z0:

Durable Objects are optimized for single-entity access. D1 is optimized for cross-entity queries.

// DO: "Give me all Facts for account_123" → Fast, local read
// D1: "Give me all charge Facts across all accounts this month" → SQL query

Data flow: DO ledger → Queue → D1 (async replication)

Constraint: D1 has eventual consistency from DO writes. Queries may lag by seconds. Use DO for authoritative reads.


What: S3-compatible object storage, zero egress fees.

z0 uses for:

  • Call recordings and transcripts (invocation context)
  • Document storage (contracts, invoices)
  • Fact archive (cold storage for old Facts)
  • Large payloads that don’t fit in DO storage

Key properties:

  • S3 API compatibility
  • No egress fees (unlike AWS S3)
  • Integrated with Workers (direct binding)
  • Unlimited storage

Why this matters for z0:

Invocations often have associated context (recordings, transcripts, images). This context is too large for DO storage but must be linked to Facts.

Fact {
type: "invocation",
data: {
recording_url: "r2://recordings/inv_123.mp3",
transcript_url: "r2://transcripts/inv_123.json"
}
}

Constraint: R2 is object storage, not a database. No querying, no indexing. Store references in D1, content in R2.


What: Message queues for decoupled, async processing.

z0 uses for:

  • Fact replication (DO → D1)
  • Webhook delivery
  • Notification dispatch
  • Non-critical background work

Key properties:

  • At-least-once delivery
  • Automatic retries with backoff
  • Dead letter queue support
  • Batch consumption

Why this matters for z0:

Not everything needs synchronous execution. Fact writes to D1 can lag. Webhook deliveries can retry. Background reconciliation can batch.

// Sync path (must be fast):
Request → Worker → DO.append_fact → Response
// Async path (can be slow):
DO.append_fact → Queue → D1.insert
→ Queue → Webhook.deliver

Constraint: At-least-once means handlers must be idempotent. Use Fact IDs for deduplication.


What: Long-running, resumable workflows with automatic state persistence.

z0 uses for:

  • Multi-step billing cycles (invoice creation → delivery → payment tracking)
  • Reconciliation runs (may take minutes, must survive failures)
  • External integrations with retry logic
  • Any process that spans multiple async steps

Key properties:

  • Automatic state persistence between steps
  • Survives Worker restarts and failures
  • Built-in retry and error handling
  • Can wait for external events (timers, webhooks)

Why this matters for z0:

Some processes take longer than Worker limits allow and must not lose progress:

Workflow: MonthlyBilling
Step 1: Query all charge Facts for period → save state
Step 2: Generate invoice documents → save state
Step 3: Deliver invoices via email → save state
Step 4: Record invoice_issued Facts → complete

If Step 3 fails, the workflow resumes from Step 3, not Step 1.

Constraint: Workflows have higher latency than direct Worker calls. Use for background processes, not real-time paths.


What: High-cardinality time-series metrics storage and query.

z0 uses for:

  • Real-time operational metrics (invocations/sec, error rates)
  • Per-tenant usage dashboards
  • Per-asset performance metrics
  • SLA monitoring and alerting

Key properties:

  • High-cardinality support (tenant_id, asset_id, tool_id as dimensions)
  • Sub-second query latency
  • 90-day retention
  • SQL-like query interface

Why this matters for z0:

Facts answer “what happened.” Analytics Engine answers “how is the system performing right now.”

// Analytics Engine query:
// "Invocations per second by tenant for the last hour"
SELECT
tenant_id,
SUM(_sample_interval) as invocations
FROM z0_invocations
WHERE timestamp > NOW() - INTERVAL '1 hour'
GROUP BY tenant_id, blob1
ORDER BY invocations DESC

Constraint: Analytics Engine is for metrics, not Facts. Facts go in DO ledgers. Metrics derived from Facts go in Analytics Engine.


z0 PrimitiveSource of TruthQuery StorageWhy
EntityDurable ObjectD1DO owns canonical state; D1 enables cross-entity queries
FactDurable Object ledgerD1 (replicated)DO ensures append-only integrity; D1 enables reporting
ConfigDurable ObjectD1 (replicated)DO enforces versioning semantics; D1 enables lookups

Each Entity gets a Durable Object. The DO ID combines the DO namespace with the Entity ID:

Entity ID: "acct_123" (includes type prefix)
DO ID: "account_acct_123" (DO namespace + entity ID)
Entity(account, "acct_123") → DO("account_acct_123")
Entity(asset, "asset_456") → DO("asset_asset_456")
Entity(contact, "cont_789") → DO("contact_cont_789")

ID Scheme:

  • Entity ID has a type prefix: acct_, asset_, cont_, deal_
  • DO ID prepends the DO class namespace: account_, asset_, contact_, deal_
  • This allows routing to the correct DO class while preserving full entity identity

The DO holds:

  • Entity metadata (mutable)
  • Fact ledger for this entity (append-only)
  • Cached state derived from Facts (reconcilable)

Facts are appended to entity DOs, then replicated to D1:

1. Worker receives invocation
2. Worker calls DO("asset_asset_456").appendFact(invocationFact)
3. DO writes to local SQLite (transactional, durable)
4. DO enqueues replication message
5. Queue consumer writes to D1
6. D1 available for cross-entity queries

Authoritative source: DO ledger (always consistent) Query source: D1 (eventually consistent, queryable)

Configs live in DOs with version management:

1. Worker requests Config update
2. DO reads current version (e.g., v3)
3. DO writes new row (v4) with effective_at = now()
4. DO updates v3 with superseded_at = now()
5. DO returns new version
6. Change replicates to D1 for queries

Single-threaded DO execution ensures no version conflicts.


Durable Objects provide single-entity transactions, but many business operations span multiple entities. z0 uses saga patterns orchestrated by Workflows to coordinate these operations.

DOs are single-entity. There’s no distributed transaction across DOs:

// This is NOT atomic:
DO("account_acct_123").deductBudget(100)
DO("account_acct_456").addBudget(100)
// If the second call fails, the first already committed.
// System is now inconsistent.

A saga is a sequence of local transactions where each step has a compensating action that undoes it on failure.

Workflow: TransferBudget(from: acct_123, to: acct_456, amount: 100)
Step 1: Reserve funds from source
Action: DO("account_acct_123").reserveBudget(100)
Compensate: DO("account_acct_123").releaseReservation(100)
Step 2: Add funds to destination
Action: DO("account_acct_456").addBudget(100)
Compensate: DO("account_acct_456").deductBudget(100)
Step 3: Confirm reservation (converts to deduction)
Action: DO("account_acct_123").confirmReservation(100)
Compensate: (none - final step)
On failure at any step:
Execute compensations in reverse order
Record failure Fact
OperationEntities InvolvedSaga Steps
Budget transferTwo accountsReserve → Add → Confirm
Contact ownership moveContact + two tenantsCreate lifecycle Fact → Update tenant_id → Record in both account ledgers
Campaign budget splitCampaign + multiple accountsValidate totals → Reserve from each → Confirm all
Charge distributionOutcome + multiple accountsCalculate splits → Record charges to each account

Workflows provide the durability needed for sagas:

workflows/transfer-budget.ts
export class TransferBudgetWorkflow extends Workflow {
async run(params: { from: string; to: string; amount: number }) {
const { from, to, amount } = params;
// Step 1: Reserve from source
const reservation = await this.step("reserve", async () => {
const fromDO = this.env.ACCOUNT_LEDGER.get(from);
return fromDO.reserveBudget(amount);
});
// Step 2: Add to destination (with compensation on failure)
try {
await this.step("add", async () => {
const toDO = this.env.ACCOUNT_LEDGER.get(to);
return toDO.addBudget(amount);
});
} catch (error) {
// Compensate: release reservation
await this.step("compensate-reserve", async () => {
const fromDO = this.env.ACCOUNT_LEDGER.get(from);
return fromDO.releaseReservation(reservation.id);
});
throw error;
}
// Step 3: Confirm reservation
await this.step("confirm", async () => {
const fromDO = this.env.ACCOUNT_LEDGER.get(from);
return fromDO.confirmReservation(reservation.id);
});
// Record completion Fact
await this.step("record", async () => {
// Both accounts get a lifecycle Fact recording the transfer
await Promise.all([
this.env.ACCOUNT_LEDGER.get(from).appendFact({
type: "lifecycle",
subtype: "budget_transferred_out",
data: { to, amount, workflow_id: this.id }
}),
this.env.ACCOUNT_LEDGER.get(to).appendFact({
type: "lifecycle",
subtype: "budget_transferred_in",
data: { from, amount, workflow_id: this.id }
})
]);
});
}
}
  1. Each step must be idempotent — Workflows may retry failed steps
  2. Compensations must be safe to run multiple times — Network failures may cause duplicate compensations
  3. Reservations over direct mutations — Reserve first, confirm later allows rollback
  4. Record all steps as Facts — Full audit trail of what happened and why
  5. Workflow ID links all Facts — Cross-entity operations can be reconstructed
FailureResultRecovery
Step fails, compensation succeedsClean rollbackNone needed
Step fails, compensation failsPartial stateManual intervention + reconciliation
Workflow crashes mid-sagaIncompleteWorkflow resumes from last saved step
Destination DO unavailableBlockedWorkflow retries with backoff

Key insight: Sagas trade atomicity for availability. The system may be temporarily inconsistent, but compensations restore consistency. This is acceptable because Facts provide the audit trail to detect and resolve issues.


Cloudflare provides infrastructure primitives. z0 adds:

GapWhat’s Missingz0 Solution
Business primitivesNo concept of Entity, Fact, ConfigPrimitives layer (PRIMITIVES.md)
Ledger semanticsDOs have SQLite, not append-only logsLedger pattern on top of DO storage
Config versioningNo built-in version managementVersion semantics in Config schema
Cross-entity transactionsDOs are single-entitySaga patterns, eventual consistency
Cached state reconciliationNo concept of derived stateReconciliation Fact pattern
Multi-tenancyBasic isolation onlytenant_id denormalization, access control
Economic attributionNo business logicAttribution calculation in Interpretation Engine
Autonomy guardrailsNo AI-specific featuresAutonomy Config + Decision Facts

Key insight: Cloudflare gives us distributed systems primitives done right. z0 adds economic truth and business semantics on top.


ScenarioUseNot
Single-entity read/writeDurable ObjectD1
Cross-entity queryD1Durable Object
Large blob storageR2D1 or DO
Async background workQueue + WorkerWorkflow
Long-running processWorkflowQueue + Worker
Real-time metricsAnalytics EngineD1
Authoritative Fact readDurable ObjectD1
Reporting queryD1Durable Object

┌─────────────────────────────────────────────────────────────┐
│ z0 on Cloudflare │
├─────────────────────────────────────────────────────────────┤
│ z0 Layer (This is what we build) │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Primitives: Entity, Fact, Config ││
│ │ Patterns: Ledger, Sharding, Reconciliation ││
│ │ Products: Call Tracking, Billing, Autonomy ││
│ └─────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│ Cloudflare Layer (This is what we use) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Workers │ │ Durable │ │ D1 │ │ R2 │ │
│ │ (compute)│ │ Objects │ │ (query) │ │ (blobs) │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Queues │ │Workflows │ │Analytics │ │
│ │ (async) │ │(durable) │ │ Engine │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘

Cloudflare provides the distributed systems foundation. z0 provides the economic truth layer. Together, they answer: “Was it worth it?”