This skill should be used when the user asks "SQL or NoSQL", "which database", how to design a "data model" or "schema design", picks an "indexing" strategy, needs "sharding" or "partitioning", sets up "replication" (leader-follower / multi-leader), defines a "primary key"/"sort key", asks whether to "denormalize", or weighs "polyglot persistence". Use it whenever a design must decide where records live, how they are keyed and accessed, and how the store scales past one node — even if the user just says "store the data".
npx skills add https://github.com/proyecto26/system-design-skills --skill data-storage
Choose where records live, how they are keyed and queried, and how the store
grows past a single machine. Storage is the hardest layer to change later: a
wrong data model or shard key calcifies into a scaling ceiling, and getting
replication wrong silently serves stale or lost data.
Any system that persists state: picking SQL vs NoSQL, designing a schema and its
access paths, adding indexes, splitting a hot table, distributing data across
nodes (sharding/partitioning), adding read replicas, or deciding what to
denormalize. Reach here the moment "store the data" needs a concrete key and
query shape.
Don't shard, add replicas, or reach for NoSQL before a number forces it (YAGNI).
A single well-indexed relational node handles ~1k QPS and tens of GB to low TB
comfortably — most systems never outgrow it. Sharding multiplies operational
cost and breaks joins/transactions; add it only when one node's write throughput
or dataset size is genuinely exceeded (→ back-of-the-envelope). Caching reads
(→ caching) and adding read replicas are cheaper first moves than sharding.
Answer these before choosing a store or topology — they decide the design:
document blobs? a graph of connections? Drives SQL vs NoSQL.
Point lookups by key, range scans, ad-hoc queries, aggregations? Model the
store around the queries it must serve.
(→ back-of-the-envelope for QPS, storage, and shard counts.)
multi-record transactions required? (CAP/consistency theory → consistency-coordination.)
data the system can afford to lose on a node failure.
Relational (SQL — Postgres, MySQL): strict schema, joins, ACID transactions.
*Use when* data is relational, integrity matters, and queries are varied/ad-hoc —
the safe default until a number rules it out.
Document (MongoDB, etc.): flexible schema, self-contained JSON-ish documents
queried by structure. *Use when* records are read/written as a whole and the
schema evolves; relationships are few.
Key-value (Redis, DynamoDB, Riak): O(1) get/put by key, no rich queries.
*Use when* access is purely by a known key and massive throughput is needed.
Wide-column (Cassandra, Bigtable, HBase): rows keyed by partition, columns
sparse, keys kept sorted for range scans. *Use when* writes are huge and the
table can be designed around a few known query patterns.
Graph (Neo4j): nodes and edges. *Use when* the core queries traverse
many-to-many relationships (social graph, recommendations).
Scaling moves (apply on top of any store):
*Use when* reads dominate and slight staleness is OK.
functional domains scale independently and rarely join.
*Use when* a single node's writes or dataset are exceeded. (This skill owns it.)
vastly outnumber writes and joins are the bottleneck.
Polyglot persistence: use more than one of the above, each for what it's best
at (e.g. Postgres for orders, Redis for sessions, a search index for full-text).
The cost is operating and reconciling several stores.
| Option | What it solves | What it worsens | Change it when |
|---|---|---|---|
| Relational/SQL | Joins, ACID, ad-hoc queries, integrity | Single-node write ceiling; schema migrations; harder horizontal scale | Writes/size exceed one node, or schema is truly fluid → NoSQL/shard |
| Document | Schema flexibility; whole-object reads | No joins; cross-document consistency is manual; query engine weaker | Data turns relational or needs multi-doc transactions → SQL |
| Key-value | Extreme throughput, simple ops | Only key access; no range/secondary queries | Queries beyond the key are needed → document/wide-column |
| Wide-column | Write-heavy scale, range scans on sorted keys | Must know queries up front; rigid once keyed; eventual by default | Access patterns are unknown/varied → relational |
| Graph | Cheap deep relationship traversal | Niche tooling; hard to shard; weak for bulk scans | Relationships are shallow → relational/document |
| Indexing | Turns scans into lookups | Slower writes; more storage; index bloat | Write amplification hurts more than the read win |
| Read replicas | Offloads reads; redundancy | Replication lag → stale reads; failover/promotion logic | Stale reads unacceptable → read-from-leader / consistency-coordination |
| Federation | Per-domain scale, smaller working sets | Cross-domain joins break; app routing logic | A single domain still won't fit → shard that domain |
| Sharding | Horizontal write + storage scale | Cross-shard joins/txns hard; resharding pain; hot shards | One node holds it fine, or hot shards dominate → consolidate/re-key |
| Denormalization | Kills expensive joins on the read path | Duplicated data; write-time fan-out; consistency drift | Write load makes fan-out the new bottleneck → normalize/cache |
Storage is where load and failure get amplified into outages.
to one node (a viral user, a single tenant) while others idle. The cluster looks
under-loaded but one shard is melting. *Mitigate:* a shard key with high
cardinality and even distribution; isolate or sub-partition hot keys.
reads go stale — and a failover may promote a follower that lost recent writes.
*Mitigate:* read-from-leader for read-your-writes; bound and alert on lag.
process/thread; a traffic spike (or a retry storm) opens more connections than
the DB can serve, and *every* query slows or errors. A pooler in front (bounded
pool) is what keeps the DB alive — without it the database is a SPOF that fails
under load.
serialize writes; index updates and lock waits stack up.
data volumes and can tip the cluster over. Plan capacity ahead of the cliff.
Monitor: replication lag, per-shard QPS and size (skew), connection-pool
saturation/wait time, slow-query rate, lock waits, and disk/IOPS headroom.
consistency need, and latency/durability targets (see *Clarify first*). No store
choice survives unknown access patterns.
default to relational until a number or relationship pattern rules it out. Name
what each candidate worsens, not just what it solves.
secondary indexes for each query before adding scale machinery (see *Interface
sketch*). The key is the decision.
caching),then read replicas, then federation, then shard. Stop at the first level that
meets the target.
exhaustion, and resharding (see *Behavior under stress*); confirm a skewed key
or write burst does not melt one node.
back-of-the-envelope; if it is one node, do not shard. Default to the generic
recipe and read the provider file only when a cloud is named.
Change it when…` table with one row per choice you made here (e.g. the
option, its store, its failure policy); the last column is a concrete trigger
(a number or observable signal). Then name what breaks first.
Do
concrete key before drawing any box.
replicas before sharding.
sub-partition known hot keys.
replication lag and per-shard skew.
Don't
failover can lose recent writes.
shards and write hotspots.
cliff.
Don't restate the tables — pull the figures from back-of-the-envelope. The ones
that drive storage decisions: a single RDBMS node ≈ 1k QPS; a key-value node
≈ 10k QPS; 10 GB fits in RAM, 10 TB needs distributed storage. Use these
to compute shard count = peak write QPS ÷ per-node QPS (and again by size =
total bytes ÷ per-node capacity), then take the larger. If the result is one
node, do not shard.
The data model *is* the contract (GUIDE failure mode #8) — a "NoSQL box" decides
nothing until the key is written. Pin down per entity:
PK = user_id (hash, spreads load), SK = created_at (sort, enables range
scans like "latest N posts"). The PK must be high-cardinality and even.
with its query.
back each query; note what is intentionally denormalized.
Without a concrete key and the query it serves, the rest of the design is
guesswork.
Default to the generic recipe above. If the user names a cloud, read
references/providers/<provider>.md for the managed-service mapping,
quotas/limits, and provider-specific trade-offs. If no file exists for that
provider, the generic recipe is the answer.
To visualize the data tier — leader with read replicas, a sharded cluster with a
router, or a polyglot split — use the in-plugin architecture-diagram skill.
Draw the shard key on the routing arrow and the replication direction explicitly;
do not embed Mermaid here.
caching — *pairs with* this for read offload and is the cheap first move;*alternative to* read replicas before sharding.
consistency-coordination — *owned-concept lives in* it: CAP/consistency models,consistent hashing, quorum, and distributed transactions/saga. *Pairs with* this
when stale reads or cross-shard atomicity are unacceptable.
back-of-the-envelope — *feeds into* this: supplies the QPS, storage, andshard-count numbers that force (or rule out) each move here.
scaling-evolution — *depends on* this block; sequences when each storage moveis introduced as a system grows.
system-design — the orchestrator that *routes into* this block.references/deep-dive.md — partitioning schemes (range/hash/directory),replication mechanics and conflict resolution, index internals (B-tree vs LSM),
normalization vs denormalization, connection pooling, resharding. Read when
designing the data tier in detail.
references/providers/{generic,aws,azure,gcp}.md — service mappings, thelimits that change a decision, and per-environment pitfalls.
Efficient database search tool for bioRxiv preprint server. Use this skill when searching for life sciences preprints by keywords, authors, date ranges, or categories, retrieving paper metadata, downloading PDFs, or conducting literature reviews.
Access BRENDA enzyme database via SOAP API. Retrieve kinetic parameters (Km, kcat), reaction equations, organism data, and substrate-specific enzyme information for biochemical research and metabolic pathway analysis.
Access ClinPGx pharmacogenomics data (successor to PharmGKB). Query gene-drug interactions, CPIC guidelines, allele functions, for precision medicine and genotype-guided dosing decisions.
Query NCBI ClinVar for variant clinical significance. Search by gene/position, interpret pathogenicity classifications, access via E-utilities API or FTP, annotate VCFs, for genomic medicine.
Access COSMIC cancer mutation database. Query somatic mutations, Cancer Gene Census, mutational signatures, gene fusions, for cancer research and precision oncology. Requires authentication.
Query Ensembl genome database REST API for 250+ species. Gene lookups, sequence retrieval, variant analysis, comparative genomics, orthologs, VEP predictions, for genomic research.
Query openFDA API for drugs, devices, adverse events, recalls, regulatory submissions (510k, PMA), substance identification (UNII), for FDA regulatory data analysis and safety research.
Query NCBI Gene via E-utilities/Datasets API. Search by symbol/ID, retrieve gene info (RefSeqs, GO, locations, phenotypes), batch lookups, for gene annotation and functional analysis.
Take proyecto26/data-storage from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.