Consistent Hashing Visualizer — Free HTML CSS JS Snippet

Consistent Hashing Visualizer · Dashboards · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Real trigonometric ring layout: x = cx + r*cos(angle), y = cy + r*sin(angle) for both server and key positions
Deterministic string hash (running multiply-add accumulator) maps every server and key name to a stable 0-359 degree angle
Consistent hashing owner lookup is a single "next server clockwise, wrap at 360" rule with no separate rebalancing step
Naive mode swaps in real hash(key) % activeServerCount modulo assignment for a literal, not simulated, side-by-side comparison
Before/after assignment diffing drives the animation — only keys whose owner actually changed get the flash-and-reroute effect
Add/Remove Server buttons pull from a fixed six-server pool so repeated demos stay deterministic and comparable
Live "Keys reassigned last change" counter turns the core claim into a comparable number, not just a visual impression
Zero dependencies, zero canvas or charting library — plain SVG line, rect, and circle elements with CSS transitions

About this UI Snippet

Consistent Hashing Visualizer — Animated Hash Ring, Minimal-Reassignment Scaling & Naive Mod-N Comparison in Vanilla JS

Screenshot of the Consistent Hashing Visualizer snippet rendered live

Consistent hashing is one of the most-referenced but least-visualized concepts in distributed systems interviews, usually summarized as "adding a node only remaps a small fraction of keys" without ever showing why. This snippet implements both consistent hashing and its naive alternative side by side, with a literal toggle between them, so the difference is something you click and watch rather than something you memorize as a bullet point.

The ring: real trigonometry, not a static image

Both servers and keys are positioned on a circle using posFor(angleDeg), which converts a 0-359 degree value into screen coordinates with x = cx + r * cos(angle) and y = cy + r * sin(angle), offset by -90 degrees so 0 degrees sits at the top of the circle and increasing angle moves clockwise. Every server and key gets its angle from hashString(name) % 360, a small deterministic hash (a running h = h * 31 + charCode accumulator, the same multiply-and-add shape as Java's String.hashCode) applied to its name string. Because the hash is deterministic, the same server or key name always lands at the same point on the ring across every render, which is exactly the property real consistent hashing depends on.

Consistent hashing: owner is "next server clockwise"

computeAssignment() in consistent mode does exactly one thing per key: it walks the currently active servers, sorted by angle, and finds the first one whose angle is greater than or equal to the key's angle — that server owns the key. If no server has a larger angle (the key is past the last server going clockwise), ownership wraps around to the server with the smallest angle, which is what makes the ring a ring instead of a line. This lookup is the entire algorithm; there is no separate rebalancing step, no explicit "move this key" logic — ownership is simply a function of where servers currently sit on the circle.

Why only nearby keys move when a server is added or removed

The critical property becomes visible in recompute(): it snapshots the previous key-to-server assignment map, recomputes a fresh one after a server is added or removed, and diffs the two, animating (a color flash plus a brief scale pulse) only the keys whose owner actually changed. When a new server is inserted at some angle X, it can only ever "steal" keys that fall between X and the previous owner going counter-clockwise from X — every key elsewhere on the ring still finds the same next-clockwise server it always did, because nothing about the ring changed at their position. Removing a server works the same way in reverse: only the keys that server owned get reassigned, to its clockwise neighbor, and every other key's nearest-clockwise-server lookup is completely unaffected. Click Add Server or Remove Server with the demo running and watch most key-to-server lines stay exactly where they are — only a small cluster near the changed node flashes and reroutes.

Naive mod-N: why almost everything moves

Toggling "Naive mod-N hashing" switches computeAssignment() to a completely different rule: owner = activeServers[hash(key) % N], where N is simply how many servers are currently active. This is the modulo-based sharding scheme many systems reach for instinctively — and its flaw is arithmetic, not incidental. Changing N by adding or removing one server changes the divisor in every single key's hash % N computation, and because the modulo operation has no relationship to the previous mapping, the vast majority of keys land on a completely different index than before, even though only one server was added or removed. With the naive toggle on, clicking Add Server or Remove Server causes nearly every line on the ring to flash and swing to a new server simultaneously — this snippet doesn't just claim that happens, the exact same diff-and-animate logic used for consistent hashing proves it happens, because it is measuring real reassignment counts from real modulo arithmetic, not a scripted animation.

Why this matters for caches and databases

A cache or database shard that uses naive mod-N hashing effectively invalidates almost its entire cache (or forces almost every key to migrate) every time capacity is scaled up or down — exactly when a system is under the most load and can least afford it. Consistent hashing keeps that migration proportional to the size of the change instead of the size of the whole cluster, which is why it underlies real systems like Amazon DynamoDB, Apache Cassandra, and most CDN and cache-sharding layers. The "Keys reassigned last change" stat in this snippet is the same number a real capacity-planning engineer cares about when deciding whether scaling an event will cause a stampede of cache misses.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Give this snippet's JavaScript to an AI assistant like Claude and ask it to trace exactly which keys get reassigned when a specific server is removed, using the actual angles computed by hashString(), to build real intuition for the "only the neighboring arc moves" property. Worthwhile extensions to ask for: virtual nodes (hashing each server to several ring positions to smooth out uneven key distribution), a manual "click anywhere on the ring to add a key at that exact hash" mode, or a running chart of reassignment count over many consecutive add/remove events comparing the two algorithms cumulatively.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build an animated consistent hashing visualizer in plain HTML, CSS, and JavaScript, no libraries or frameworks.

Requirements:
- Render a circular hash ring in SVG using real trigonometry (x = cx + r*cos(angle), y = cy + r*sin(angle)) with a handful of server nodes and several key markers, all positioned by feeding their name strings through a small deterministic hash function that maps to a 0-359 degree angle.
- Implement consistent hashing assignment as "each key belongs to the next server clockwise from its position on the ring, wrapping around to the first server if none is found," and draw a colored line from each key to its currently assigned server.
- Add "Add Server" and "Remove Server" controls that add or remove a server from a fixed pool, then recompute assignments and animate (brief highlight plus a reroute of its connecting line) only the keys whose assigned server actually changed as a result — every unaffected key's line must visibly stay exactly where it was.
- Add a toggle for "naive mod-N hashing" that swaps the assignment rule to hash(key) % currentServerCount, so the exact same add/remove-server action can be replayed under the naive rule and cause nearly all keys to flash and reroute simultaneously, in direct visual contrast to the minimal reassignment under consistent hashing.
- Track and display a live count of how many keys were reassigned by the most recent add/remove action, so the contrast between the two algorithms is a comparable number and not just a visual impression.
- Use a fixed, deterministic pool of server names (not random generation) so repeated demo runs produce the same ring layout and are directly comparable to each other.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Look at the ring with 4 active servers and 10 keysEach key is a small dot connected by a colored line to the square server node that owns it — the line color matches its owning server's color in the legend below.
  2. 2
    Click Add Server with consistent hashing active (default)A new square node fades in at its hashed position on the ring. Watch closely: only the handful of keys between the new node and its counter-clockwise neighbor flash and reroute — every other line stays exactly where it was.
  3. 3
    Click Remove Server a couple of timesOnly the keys owned by the removed server flash and re-route to its clockwise neighbor. The rest of the ring, including lines untouched by the change, stays completely still.
  4. 4
    Check the "Naive mod-N hashing" boxThe Mode stat switches to "Naive mod-N" and assignments recompute using hash(key) % serverCount instead of the ring-walk rule.
  5. 5
    Click Add Server or Remove Server again with naive mode onThis time nearly every line on the ring flashes at once and swings to a different server — the "Keys reassigned last change" counter jumps close to the total key count instead of staying small.
  6. 6
    Toggle back to consistent hashing and repeat an add/removeCompare the reassignment counters directly: consistent hashing's number stays small and proportional to the change; naive mod-N's number stays close to the full key count every time.

Real-world uses

Common Use Cases

System design interview preparation for caching and sharding questions
Consistent hashing is one of the most frequently asked system design topics for roles touching caching, databases, or CDNs. Toggling between the two modes and watching real reassignment counts builds the concrete intuition needed to explain "why" during an interview, not just recite the term. Pairs well with the token bucket rate limiter visualizer for a broader distributed-systems demo set.
Capacity planning and scaling-impact dashboards
Adapt the assignment-diff logic into an internal tool that estimates real cache-miss or shard-migration impact before a capacity change ships, replacing the simulated servers and keys with actual node and shard identifiers from your infrastructure.
Reference implementation before writing a real hash ring
The next-clockwise-server lookup and the wrap-around edge case are the two things people most often get wrong implementing consistent hashing from scratch; this snippet's computeAssignment() function is a minimal, readable reference for both.
Teaching material for a distributed systems or backend course
Embed as a live, clickable demo in course material or a technical blog post on distributed caching, letting readers trigger their own add/remove events and naive-mode toggles instead of reading a single static ring diagram.
Explaining a scaling incident retroactively
If a past capacity change caused a cache-miss stampede, reproducing the old hashing scheme (naive mode) against the new one (consistent mode) in this visualizer is a fast, concrete way to show a team exactly why the migration was so disruptive and how switching schemes would prevent a repeat.

Got questions?

Frequently Asked Questions

Yes. The hash function, ring math, and computeAssignment() are all pure functions with no DOM references, so they move directly into a utility module. There is no animation loop or interval to clean up here — every animation is a CSS transition triggered by attribute changes, so React can drive it by storing servers/keys/assignment in state and re-rendering SVG elements declaratively (add a key={name} to each line/dot so React reuses the same DOM node and the CSS transition still fires). In Vue, keep the same state in a reactive ref and use :key bindings for the same reason. In Angular, use *ngFor with trackBy on the server/key name so existing SVG elements are reused rather than destroyed and recreated, which is what makes the position and color transitions animate instead of snapping.

In consistent hashing, ownership is "the next server clockwise from a key's position" — inserting a new server only changes that answer for keys that fall between the new server and whatever server used to be next-clockwise from that spot; every other key's next-clockwise server is unchanged because nothing about the ring changed at their location. In naive mod-N hashing, ownership is hash(key) % serverCount, and changing serverCount changes the divisor for every single key's modulo calculation simultaneously, so nearly every key lands on a different index purely from the arithmetic, regardless of where it was before.

This snippet uses a simple deterministic string hash (h = h * 31 + charCode for each character, mod 360) purely to get a stable, readable 0-359 angle for demo purposes. Production consistent-hashing implementations use a proper hash function like MD5, MurmurHash, or SHA-1 over a much larger keyspace (commonly 2^32 or 2^64 positions) and typically place multiple "virtual node" points per physical server around the ring to smooth out uneven key distribution, both of which are reasonable next steps if you extend this snippet toward production use.

The ring wraps around: computeAssignment() falls back to the server with the smallest angle when no server has an angle greater than or equal to the key's angle, which correctly models a circle rather than a line with a dead end at 359 degrees. This wrap-around case is exactly the part of consistent hashing that is easiest to get wrong in a from-scratch implementation.

Using a fixed pool (server-a through server-f) with pre-hashed, fixed ring angles keeps every demo run deterministic and directly comparable — clicking Add Server and Remove Server always produces the same before/after ring layout, which makes it possible to trust the reassignment counts you see rather than wondering if a random hash placement happened to be unusually lucky or unlucky.