Skip to main content

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-server and the nats CLI 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.

#!/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.

#!/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.

#!/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.

#!/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.