NoSQL databases are broadly categorized into four types, based on how they store and retrieve data:
Key-Value Stores
Document Stores
Column-Family Stores
Graph Databases
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Four Types of NoSQL Databases</title>
<style>
.infographic-nosqltabs {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--on-accent: #ffffff;
--display-font: Georgia, 'Iowan Old Style', serif;
--body-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--mono-font: 'SF Mono', Consolas, monospace;
background: var(--paper);
color: var(--ink);
font-family: var(--body-font);
max-width: 900px;
margin: 0 auto;
box-sizing: border-box;
overflow-x: hidden;
}
.infographic-nosqltabs[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--on-accent: #101418;
}
.infographic-nosqltabs * { box-sizing: border-box; }
.nx-head { text-align: center; margin-bottom: 0.25rem; }
.nx-head h2 {
font-family: var(--display-font);
font-size: 1.95rem;
margin: 0 0 0.5rem;
}
.nx-head p {
color: var(--ink-soft);
font-size: 1rem;
margin: 0 auto;
max-width: 560px;
line-height: 1.55;
}
.nx-tabs { display: flex; justify-content: center; gap: 0.5rem; margin: 1.75rem 0 0; flex-wrap: wrap; }
.nx-tab {
font: inherit;
font-size: 0.85rem;
background: var(--paper-alt);
border: 1px solid var(--line);
border-radius: 999px;
padding: 0.5rem 1.05rem;
cursor: pointer;
color: var(--ink-soft);
}
.nx-tab:hover { border-color: var(--accent); }
.nx-tab.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.nx-panel { display: none; margin-top: 1.5rem; }
.nx-panel.is-active { display: block; animation: nx-fade 0.2s ease; }
@keyframes nx-fade { from { opacity: 0; } to { opacity: 1; } }
.nx-frame { background: var(--paper-alt); border: 1px solid var(--line); border-radius: 10px; padding: 1.25rem; }
.nx-desc { font-size: 0.9rem; color: var(--ink-soft); line-height: 1.55; margin: 0 0 1.1rem; text-align: center; }
.nx-visual-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; }
/* key-value visual */
.nx-kv-list { display: flex; flex-direction: column; gap: 0.5rem; min-width: 260px; }
.nx-kv-row { display: flex; gap: 0.6rem; align-items: center; }
.nx-kv-key { font-family: var(--mono-font); font-size: 0.8rem; background: var(--accent); color: var(--on-accent); border-radius: 6px; padding: 0.3rem 0.6rem; flex-shrink: 0; }
.nx-kv-val { font-family: var(--mono-font); font-size: 0.78rem; background: var(--paper); border: 1px solid var(--line); border-radius: 6px; padding: 0.3rem 0.6rem; flex: 1; }
/* document visual */
.nx-doc-row { display: flex; gap: 0.9rem; flex-wrap: wrap; min-width: 260px; }
.nx-doc-card { flex: 1 1 180px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 0.75rem 0.9rem; font-family: var(--mono-font); font-size: 0.76rem; line-height: 1.55; min-width: 0; }
.nx-doc-card .k { color: var(--accent); }
.nx-doc-card .missing { color: var(--ink-soft); font-style: italic; }
/* column visual */
.nx-col-row { display: flex; gap: 0.7rem; flex-wrap: wrap; min-width: 260px; }
.nx-col-block { flex: 1 1 100px; min-width: 0; }
.nx-col-head { background: var(--accent); color: var(--on-accent); font-size: 0.72rem; font-weight: 700; border-radius: 6px 6px 0 0; padding: 0.35rem 0.5rem; text-align: center; }
.nx-col-cell { background: var(--paper); border: 1px solid var(--line); border-top: none; font-family: var(--mono-font); font-size: 0.76rem; padding: 0.35rem 0.5rem; text-align: center; }
.nx-col-cell.is-null { color: var(--ink-soft); font-style: italic; }
.nx-col-cell:last-child { border-radius: 0 0 6px 6px; }
/* graph visual */
.nx-graph-scroll svg { width: 100%; height: auto; display: block; min-width: 300px; }
.nx-node-circle { fill: var(--accent); }
.nx-node-text { fill: var(--on-accent); font-size: 13px; font-weight: 700; font-family: var(--body-font); text-anchor: middle; }
.nx-edge { stroke: var(--ink-soft); stroke-width: 2; fill: none; }
.nx-edge-label { fill: var(--ink-soft); font-size: 11px; font-style: italic; font-family: var(--body-font); }
.nx-info-row { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-top: 1.1rem; }
.nx-info-chip { flex: 1 1 200px; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 0.6rem 0.8rem; font-size: 0.82rem; }
.nx-info-chip .lbl { display: block; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-soft); margin-bottom: 0.2rem; }
@media (prefers-reduced-motion: reduce) {
.infographic-nosqltabs *, .infographic-nosqltabs *::before, .infographic-nosqltabs *::after {
transition-duration: 0.001ms !important;
animation-duration: 0.001ms !important;
}
}
</style>
</head>
<body>
<div class="infographic-nosqltabs" id="nosqltabs">
<div class="nx-head">
<h2>The Four Types of NoSQL Databases</h2>
<p>Same idea, four different shapes. Click through to see how each one actually structures data.</p>
</div>
<div class="nx-tabs">
<button class="nx-tab" data-tab="kv" type="button">📋 Key-Value</button>
<button class="nx-tab" data-tab="doc" type="button">📦 Document</button>
<button class="nx-tab" data-tab="col" type="button">📊 Column-Family</button>
<button class="nx-tab" data-tab="graph" type="button">🌐 Graph</button>
</div>
<!-- Key-Value -->
<div class="nx-panel" data-panel="kv">
<div class="nx-frame">
<p class="nx-desc">A unique key mapped to an opaque value. No schema, no query language beyond "give me the value for this key" — just extremely fast lookups.</p>
<div class="nx-visual-scroll">
<div class="nx-kv-list">
<div class="nx-kv-row"><span class="nx-kv-key">user:101</span><span class="nx-kv-val">{"name":"Alice","plan":"pro"}</span></div>
<div class="nx-kv-row"><span class="nx-kv-key">user:102</span><span class="nx-kv-val">{"name":"Bob"}</span></div>
<div class="nx-kv-row"><span class="nx-kv-key">session:abc</span><span class="nx-kv-val">userId=101, expires=2026-08-01</span></div>
</div>
</div>
<div class="nx-info-row">
<div class="nx-info-chip"><span class="lbl">Examples</span>Redis, DynamoDB</div>
<div class="nx-info-chip"><span class="lbl">Best for</span>Caching, session storage, feature flags</div>
</div>
</div>
</div>
<!-- Document -->
<div class="nx-panel" data-panel="doc">
<div class="nx-frame">
<p class="nx-desc">Stores JSON-like documents. Each record only holds the fields it actually needs — no forced NULLs, no rigid schema.</p>
<div class="nx-visual-scroll">
<div class="nx-doc-row">
<div class="nx-doc-card">{<br> <span class="k">name</span>: "Alice",<br> <span class="k">email</span>: "alice@mail.com",<br> <span class="k">hobbies</span>: ["Reading","Chess"]<br>}</div>
<div class="nx-doc-card">{<br> <span class="k">name</span>: "Bob",<br> <span class="k">email</span>: "bob@mail.com"<br><span class="missing"> // no hobbies field</span><br>}</div>
</div>
</div>
<div class="nx-info-row">
<div class="nx-info-chip"><span class="lbl">Examples</span>MongoDB, CouchDB</div>
<div class="nx-info-chip"><span class="lbl">Best for</span>Content management, product catalogs, user profiles</div>
</div>
</div>
</div>
<!-- Column-Family -->
<div class="nx-panel" data-panel="col">
<div class="nx-frame">
<p class="nx-desc">Data is grouped by column instead of by row, so scanning one attribute across millions of records stays fast.</p>
<div class="nx-visual-scroll">
<div class="nx-col-row">
<div class="nx-col-block">
<div class="nx-col-head">Name</div>
<div class="nx-col-cell">Alice</div>
<div class="nx-col-cell">Bob</div>
<div class="nx-col-cell">Carol</div>
</div>
<div class="nx-col-block">
<div class="nx-col-head">Dept</div>
<div class="nx-col-cell">HR</div>
<div class="nx-col-cell">Sales</div>
<div class="nx-col-cell">HR</div>
</div>
<div class="nx-col-block">
<div class="nx-col-head">Login</div>
<div class="nx-col-cell">09:01</div>
<div class="nx-col-cell is-null">—</div>
<div class="nx-col-cell">09:14</div>
</div>
</div>
</div>
<div class="nx-info-row">
<div class="nx-info-chip"><span class="lbl">Examples</span>Cassandra, HBase</div>
<div class="nx-info-chip"><span class="lbl">Best for</span>Time-series data, large-scale analytics</div>
</div>
</div>
</div>
<!-- Graph -->
<div class="nx-panel" data-panel="graph">
<div class="nx-frame">
<p class="nx-desc">Data is modeled as nodes and edges. Relationships are stored directly, instead of being computed with joins.</p>
<div class="nx-visual-scroll nx-graph-scroll">
<svg viewBox="0 0 500 200" role="img" aria-label="Graph of Alice, Bob, and Carol with follows relationships">
<defs>
<marker id="nxArrow" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto">
<path d="M0,0 L8,4 L0,8 z" fill="var(--ink-soft)"></path>
</marker>
</defs>
<path class="nx-edge" d="M120,100 L220,50" marker-end="url(#nxArrow)"></path>
<text class="nx-edge-label" x="140" y="68">follows</text>
<path class="nx-edge" d="M380,100 L260,50" marker-end="url(#nxArrow)"></path>
<text class="nx-edge-label" x="320" y="68">follows</text>
<circle class="nx-node-circle" cx="240" cy="32" r="34"></circle>
<text class="nx-node-text" x="240" y="37">Alice</text>
<circle class="nx-node-circle" cx="90" cy="118" r="34"></circle>
<text class="nx-node-text" x="90" y="123">Bob</text>
<circle class="nx-node-circle" cx="410" cy="118" r="34"></circle>
<text class="nx-node-text" x="410" y="123">Carol</text>
</svg>
</div>
<div class="nx-info-row">
<div class="nx-info-chip"><span class="lbl">Examples</span>Neo4j, ArangoDB</div>
<div class="nx-info-chip"><span class="lbl">Best for</span>Social networks, recommendation engines, fraud detection</div>
</div>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.getElementById('nosqltabs');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
(function () {
const tabs = document.querySelectorAll('.nx-tab');
const panels = document.querySelectorAll('.nx-panel');
function showTab(n) {
tabs.forEach(t => t.classList.toggle('is-active', t.dataset.tab === n));
panels.forEach(p => p.classList.toggle('is-active', p.dataset.panel === n));
}
tabs.forEach(t => t.addEventListener('click', () => showTab(t.dataset.tab)));
showTab('kv');
})();
</script>
</body>
</html>.demo {
font-family: system-ui, sans-serif;
padding: 16px;
}
.demo h1 {
color: #2563eb;
margin: 0 0 8px;
}
.demo p {
color: #4b5563;
margin: 0;
}document.querySelector('.demo h1')?.addEventListener('click', () => {
alert('Hello from live preview!');
});