Skip to main content

4. Persist messages with JetStream

So far your messages have been fleeting: a subscriber that isn't listening at the moment you publish never sees them. In this tutorial you turn on JetStream, create a stream that stores messages durably, publish a few, and then replay them from the very beginning. By the end you'll have proof that the messages survived, sitting in storage, ready to read again.

What you'll need​

  • nats-server and the nats CLI installed (from Hello NATS).
  • A terminal. You'll start the server in one and run commands in another.

Step 1: Start the server with JetStream​

Stop any server you started earlier, then start a new one with the -js flag. That flag turns on JetStream, the subsystem that stores messages.

nats-server -js

You should see a startup log that mentions JetStream, including a line like:

[INF] Starting JetStream
[INF] Server is ready

Leave this running. Open a second terminal for the remaining steps.

Step 2: Create a stream​

In the second terminal, create a stream named EVENTS that captures every subject beginning with events.. The --defaults flag fills in sensible starting values so you aren't prompted for anything.

#!/bin/bash

# Create a stream named EVENTS that captures every subject under events.>
# --defaults fills in sensible starting values so the CLI does not prompt.
nats stream add EVENTS --subjects "events.>" --defaults

You should see output ending with:

Stream EVENTS was created

Your stream now exists and is waiting for messages.

Step 3: Publish a few messages​

Publish three messages to subjects under events.. Because each subject matches the stream, the server stores every one.

#!/bin/bash

# Publish three messages. Each subject starts with events. so the EVENTS
# stream captures and stores every one. For each publish the CLI prints a
# "Stored in Stream" line with the assigned sequence, confirming it was stored.
nats pub events.page_loaded '{"page":"/home"}' --jetstream
nats pub events.input_changed '{"field":"email"}' --jetstream
nats pub events.page_loaded '{"page":"/pricing"}' --jetstream

For each publish you should see two lines: one confirming the message was sent, and one confirming the stream stored it with an assigned sequence number:

13:42:01 Published 16 bytes to "events.page_loaded"
13:42:01 Stored in Stream: EVENTS Sequence: 1
13:42:01 Published 17 bytes to "events.input_changed"
13:42:01 Stored in Stream: EVENTS Sequence: 2
13:42:01 Published 19 bytes to "events.page_loaded"
13:42:01 Stored in Stream: EVENTS Sequence: 3

Confirm the stream now holds three messages:

nats stream info EVENTS

You should see a State block reporting three messages:

State:

Messages: 3
Bytes: 159 B
First Sequence: 1 @ 2026-06-09 13:42:01
Last Sequence: 3 @ 2026-06-09 13:42:01
Active Consumers: 0
Number of Subjects: 2

Step 4: Replay the stored messages​

Now read the messages back. This replays every message the stream holds, oldest first, starting from the very first one. Nothing is removed: replaying a stream is a read.

#!/bin/bash

# Replay every message stored in the stream, oldest first.
# --all start at the first stored message (sequence 1)
# --terminate-at-end stop once all stored messages have been read
nats sub "events.>" --all --terminate-at-end

You should see all three messages, in the order they were published:

[#1] Received JetStream message: stream: EVENTS seq: 1 / pending: 2 / subject: events.page_loaded / time: 2026-06-09 13:42:01
{"page":"/home"}

[#2] Received JetStream message: stream: EVENTS seq: 2 / pending: 1 / subject: events.input_changed / time: 2026-06-09 13:42:01
{"field":"email"}

[#3] Received JetStream message: stream: EVENTS seq: 3 / pending: 0 / subject: events.page_loaded / time: 2026-06-09 13:42:01
{"page":"/pricing"}

The command exits on its own once it's read everything stored. Run it again and you'll see the same three messages: the stream still has them.

What you built​

You enabled JetStream, created the EVENTS stream, published three messages into it, and replayed all three back from storage. And they were still there to read again afterward.

Next​