NATS Jam

Every note you play is a NATS message round-tripping through a Raspberry Pi

🎹 The Piano fan-out

Play with your mouse, or keys A–' (white) and WE TYU… (black) Β· Z/X shift octave

πŸ€– The Band queue group

Add bots, or tap a βœ• to kill one Β· Watch every note still land on only one of them as the queue group rebalances

βͺ Time Machine JetStream

Replay the last minutes at up to 8Γ— Β· Watch old notes play back from the always-recording PIANO stream β€” no record button needed

πŸš’ Firehose throughput

Blast thousands of notes/sec through the broker at once Β· Watch the messages/sec graph spike while your own notes still play instantly

🎹 Start Here

This is a multiplayer piano β€” but really it's a live demo of NATS, an open-source messaging system. Every note anyone plays becomes a NATS message that travels to a broker running on a Raspberry Pi and back out to everyone here. The app exists to make NATS's core ideas something you can see and hear instead of read about.

The one core idea

Normally, programs talk to each other directly: your app calls a server's URL, waits for a response, and both sides have to know about each other β€” addresses, retries, what to do when the other side is down. NATS replaces that with something more like a group chat: every program connects to one central broker and publishes messages to named channels (NATS calls them subjects, like piano.note.64). Anyone who told the broker they're interested in a subject gets the message instantly. The sender doesn't know or care who's listening β€” could be nobody, could be fifty browsers.

How to explore

Play something β€” with friends, ideally. Then work through each part in turn: the piano and the three cards below it each showcase a different NATS capability, and each has its own β“˜ explaining what you're looking at. The right-hand panel shows what's happening under the hood the whole time β€” the wire tap at the bottom is every raw message your browser receives; click a row to see the payload.

🎹 The Piano β€” fan-out pub/sub

Press a key and your browser publishes one tiny message to a subject like piano.note.64 ("someone played E4") β€” that's all it does. Every other browser has subscribed to piano.note.> (the > is a wildcard that matches every note), so the broker hands each of them a copy and everyone's key lights up at once. No user list, no loop sending to each connection β€” broadcasting to whoever is interested isn't something the app builds, it's simply what publishing to a subject does.

Even your own key only lights when your message comes back from the Pi, so the latency you feel is real, not a local animation. The green ● badge in the panel on the right measures that round trip continuously β€” that's NATS's request-reply pattern: ask a question, get an answer, like HTTP but over the same connection.

This is the foundation the other three cards build on. They're all the same move β€” publish to a subject β€” with small changes in who is listening and what the broker remembers.

πŸ€– The Band β€” queue groups

Sometimes broadcast is exactly wrong. Imagine a sign-up form that should trigger a welcome email, and three copies of your email-sender running for redundancy. If all three subscribe normally, all three receive each "new user!" message β€” and every new user gets three welcome emails. News should go to everyone; jobs should be done once. The traditional fix is more infrastructure: a queue server, a load balancer, a dispatcher tracking which workers are busy.

In NATS the fix is one extra word. When subscribing, a program may give a group name. Subscribers that share a group name are treated as one team, and the broker delivers each message to exactly one member, spread roughly evenly. Subscribers without a group still each get their own copy. Both rules apply to the same message at the same time: when you play a note, every browser gets a copy (no group), and exactly one bot from the group band claims it and answers musically. That's why one note gets one reply β€” maybe Echo an octave up, maybe Bassline underneath β€” instead of a wall of noise from every bot at once. The β™ͺ counters on the bot chips show the broker spreading the work.

Sliding the band bigger is what "scaling up" really is: a new worker subscribes with the same group name and immediately starts receiving its share. No registration, no config push, no rebalancing procedure.

Removing a bot β€” what failure costs

Tap the βœ• on any bot to remove it mid-song. In most architectures, "we chose to run fewer workers" and "a worker crashed" are wildly different events; the second one triggers health checks, alerts, failover logic, connection draining. In NATS there is no separate failure path: a subscriber that's gone β€” politely or violently β€” simply stops being picked, and the very next message goes to a surviving teammate. Planned departure and crash have the same consequence: none. The music never stutters, and the bot slider just ticks down. (You'll see the removal go by on jam.control.kill in the wire tap. Killing workers on purpose to prove resilience is a real practice called chaos engineering.)

βͺ Time Machine β€” JetStream

Plain NATS messages are fire-and-forget, like radio: if you weren't tuned in, you missed it. For the piano that's fine β€” but real systems often can't afford to miss things. JetStream is the optional recorder bolted onto the broker: you tell it which subjects to keep, and it writes every matching message to disk as it flies past.

This app told JetStream to keep everything on piano.note.> in a stream named PIANO β€” which is why there's no record button: it was always recording, from the moment the service started. Hitting Replay just asks the broker to re-deliver from a point in time, and the speed knob works because every stored message has its original timestamp. You can replay something you played before this page was even open.

Real systems lean on this constantly: a consumer that crashes resumes exactly where it left off instead of losing data; a brand-new service can join months later and catch up on the whole history; and the stream doubles as an audit log of everything that ever happened. The JetStream Β· PIANO panel on the right shows the stream's size and age changing live as you play.

πŸš’ Firehose β€” throughput

Everything this page demonstrates would matter less if the broker were heavy or fragile. It isn't: NATS is a single small binary using a few megabytes of memory β€” and this one is running on a Raspberry Pi in a home rack.

The firehose makes that concrete: it publishes up to 5,000 notes per second through the same broker you're playing through. While it runs, keep playing β€” your notes still arrive instantly, nothing is dropped, and the messages-per-second graph on the right tells the real story. (Your ears are spared on purpose: past ~40 notes/sec the page renders the flood visually but stops giving every note a voice.)

Two honest footnotes: the wire tap collapses into "Γ—N msgs this frame" rows during the burst β€” that's the page protecting the browser DOM, not NATS struggling. And since firehose notes land on piano.note.> like any other note, they're recorded by JetStream too β€” check the stream counter after a burst. In production, the same binary handles millions of messages per second on real hardware.