managed-datastore-write-cost-discipline
Managed Datastore Write-Cost Discipline — Aggregate Before You Write
Section titled “Managed Datastore Write-Cost Discipline — Aggregate Before You Write”Managed row-billed stores (Cloudflare D1, Postgres-per-row insert paths, DynamoDB write units) bill per row or per operation written and scanned, not per byte stored. Raw event payloads written 1:1 are the single most expensive thing you can do with them.
- Aggregate before you write. Only aggregated, calculated, or otherwise reduced data goes into a row-billed datastore. The raw event stream never does. If you cannot name the aggregation or reduction a row represents, it does not belong there.
- Raw data stays in object storage or is computed at query time. Object storage (Cloudflare R2 equivalent: no egress, cheap ops) holds raw event payloads keyed by ID/timestamp; anything re-derivable at query time is not persisted at all.
- Watch the read-scan bill, not just the write bill. Row-billed stores charge rows
scanned by the query planner, not rows returned. One unindexed
WHEREover an N-row table bills N rows read per query — a “cheap” read path is how a future surprise bill arrives. - Index every filtered column,
LIMITevery scan, avoidSELECT *over wide tables. NeverCOUNT(*)a growing table on a hot path — maintain a counter column/row instead. - Warn before you write or scan, not after. Before any command that writes to or scans a
managed datastore (D1
INSERT/UPDATE/batch,wrangler d1 execute, bulk R2 ops, a migration), state the estimated row/operation count and its dollar cost at the current published rate — then proceed. Unknown volume is itself the warning: say “volume unknown, could be unbounded” rather than staying silent. Pairs withmodules/t1k-base/rules/preview-first-batch.md(smoke a small N, surface it, confirm before scaling) — cite that rule’s mechanics rather than repeating them here.
Decision table
Section titled “Decision table”| Data shape | Home |
|---|---|
| Raw event / payload / blob (analytics, logs, fails) | Object storage (R2-class), or compute at query time |
| Rollup / daily aggregate / KPI / config | Row-billed store (D1-class) |
| Hot counter (user count, DAU, fails) | Maintained counter column — never COUNT(*) on a hot path |
| Short-lived ephemeral | Local compute — do not persist |
Why: D1 bills write rows beyond the included 50M/mo at ~$1.00/M while read rows beyond
25B/mo bill ~$0.001/M — writes are ~1000× the per-row price of reads, and an unindexed scan
bills every row it touches. Worked example, incident, and full pricing table:
docs/datastore-cost-discipline.md.
Related
Section titled “Related”rules/docker-volume-discipline.md— the sibling incident: an un-audited store pattern that silently became the expensive defaultskills/t1k-datastore-cost/SKILL.md— the operational playbook (store choice, aggregate pipeline, index review, pre-deploy cost check)