6. Store state in Key-Value
You'll create a Key-Value bucket, put a value into it, read it back, and then watch the bucket from a second terminal so you see changes the moment they happen. By the end you'll have a tiny live state store you can read, write, and observe.
What you'll need
nats-serverand thenatsCLI installed (see 1. Hello NATS).- A Key-Value bucket is backed by a JetStream stream, so you'll start the server with JetStream enabled in Step 1.
Step 1: Start the server with JetStream
A Key-Value bucket is stored in JetStream, so start the server with the
-js flag.
nats-server -js
You should see a startup log line confirming JetStream is on:
[INF] Starting JetStream
[INF] Server is ready
Leave this running and open a new terminal for the next steps.
Step 2: Create a bucket
Create a bucket called profiles. This is where your values will live.
- CLI
#!/bin/bash
# Create a Key-Value bucket called profiles. A bucket is where your
# values live.
nats kv add profiles
# You should see a confirmation with the bucket name and config:
#
# Information for Key-Value Store Bucket profiles created 2026-06-09 10:13:41
#
# Configuration:
#
# Bucket Name: profiles
# History Kept: 1
# ...
# Backing Store Kind: JetStream
You should see a confirmation with the bucket's configuration:
Information for Key-Value Store Bucket profiles created 2026-06-09 10:13:41
Configuration:
Bucket Name: profiles
History Kept: 1
...
Backing Store Kind: JetStream
Step 3: Put a value and read it back
Store a value under a key, then get it back. The key is sue.color and the
value is blue.
- CLI
#!/bin/bash
# Put a value: the key is sue.color, the value is blue.
nats kv put profiles sue.color blue
# You should see the value echoed back with its revision:
#
# blue
# Get the value back out by its key.
nats kv get profiles sue.color
# You should see the full entry, including the value:
#
# profiles > sue.color revision: 1 created @ ...
#
# blue
The put echoes the value back, and the get returns the full entry:
blue
profiles > sue.color revision: 1 created @ ...
blue
You now have one value stored and confirmed.
Step 4: Watch the bucket from a second terminal
A watch streams every change to the bucket as it happens. Open a second
terminal and start watching profiles.
- CLI
#!/bin/bash
# Watch the whole profiles bucket. On start it replays the current value
# of every key, then blocks and prints each change live until you stop it
# with Ctrl-C. Run this in its own terminal.
nats kv watch profiles
# You should see the current value first, then it waits:
#
# [2026-06-09 10:14:22] PUT profiles > sue.color: blue
The watch first replays the current value, then waits:
[2026-06-09 10:14:22] PUT profiles > sue.color: blue
Leave the watch running. Here's the flow you've just set up: a writer puts a value, and the watcher receives it live.
Step 5: Update the value and see the watch fire
Back in your first terminal, put a new value for the same key.
- CLI
#!/bin/bash
# Put a new value for the same key. This is a normal put: it overwrites
# whatever was there.
nats kv put profiles sue.color green
# You should see the new value echoed back:
#
# green
#
# In the terminal running the watch, a new line appears the instant this
# lands:
#
# [2026-06-09 10:15:03] PUT profiles > sue.color: green
The put returns the new value:
green
Switch to the watch terminal. A new line appears the instant the change lands:
[2026-06-09 10:15:03] PUT profiles > sue.color: green
Stop the watch with Ctrl-C when you're done.
What you built
You have a Key-Value bucket holding live state: you put and got a value, and a watcher in a second terminal received every change the moment it happened.
Next
- Capstone: 7. Build an app — combine publish/subscribe, request/reply, and a stream in one program.
- Now understand how this works: the Key-Value deep dive explains buckets, revisions, watching, and the stream underneath.