This section of the documentation contains the reference documentation for the NATS network protocols used between clients applications and server and between nats servers interconnected in a cluster.
The virtues of the NATS protocol manifest quickly when you experience how easy it is to use NATS. Because the NATS protocol is text-based, you can use NATS across virtually any platform or language.
In the following demo we use Telnet. On the wire you can publish and subscribe using a simple set of protocol commands.
Open a terminal and initiate a connection to the NATS demo instance.
The expected result will roughly look like this. Note the IP address, and INFO payload may have different values.
Any client establishing a connection with the server must send CONNECT message to confirm the connection. There are several options that can be specified to indicate the client supported features, but for the purpose of this example, we can send an empty payload.
You will see a +OK message in response.
Not long after the CONNECT you will see a PING message. There is a bi-directional behavior between the client and server to check for liveness. In the case of the server, after some period of time without a PONG, the server will shutdown the client connection. If the client does not hear back a PONG, it will attempt to reconnect to a different server in a clustered setup, if available.
You can respond to the server, but simply typing PONG followed by a return.
Subscribe to the wildcard subject foo.* with subscription ID of 90.
An +OK message will follow, indicating a successful subscription.
NATS connection are bi-directional, so we can not only subscribe to subjects, but we can publish to them as well.
We can send the PUB command followed by the subject, and the length of the message payload that will be followed on the second line. In this case, hello is the payload. Once that is typed, hit return which will send the message.
An +OK message will follow, indicating a successful publish.
Immediately following, a MSG message will appear which indicates the subscription received the message that was just published.
You can use the UNSUB command to unsubscribe from a message.
Run the subscriber to unsubscribe:
Now that we unsubscribed, if we attempt to publish again, we will receive the +OK, but will not receive a MSG.
Use ctrl+c to close the connection, however, as noted above, if this is not done, after some period of inactivity the server will automatically close the connection.
telnet demo.nats.io 4222Trying 107.170.221.32...
Connected to demo.nats.io.
Escape character is '^]'.
INFO {"server_id":"NCXMJZYQEWUDJFLYLSTTE745I2WUNCVG3LJJ3NRKSFJXEG6RGK7753DJ","version":"2.0.0","proto":1,"go":"go1.11.10","host":"0.0.0.0","port":4222,"max_payload":1048576,"client_id":5089}CONNECT {}PONGSUB foo.* 90PUB foo.bar 5
helloMSG foo.bar 90 5
helloUNSUB 90PUB foo.bar 7
goodbyeThis guide provides you with considerations for developing NATS clients, including:
CONNECT handling
Authorization
Verbose (acks)
Pedantic mode
Ping/pong interval
Parsing the protocol
Deciding on a parsing strategy
Storing and dispatching subscription callbacks
Implementing requests/response
Error handling, disconnecting and reconnecting
Cluster support
Probably the best way to learn about implementing a client is to look at one of the client's maintained by the Synadia team. These clients are generally full featured, so if you can use them, that is even better, but if you have to write a client these may go beyond your needs while still capturing many of the design considerations discussed here.
See for more links and community supported languages.
Clients can connect in authenticated or unauthenticated mode, as well as verbose mode which enables acknowledgements. See the for details.
By default clients can connect to the server in unauthenticated mode. You can configure the NATS server to require password authentication to connect.
For example, using the command line:
The client must then authenticate to connect to the server. For example:
When 'verbose' is enabled (via the CONNECT message), the NATS server will return +OK to acknowledge receipt of a valid protocol message. The NATS server automatically runs in verbose mode. Most client implementations disable verbose mode (set it to false in the CONNECT message) for performance reasons.
A client may also support 'pedantic' mode. Pedantic mode indicates to the server that strict protocol enforcement is required.
NATS implements auto-pruning. When a client connects to the server, the server expects that client to be active. Periodically, the NATS server pings each subscriber, expecting a reply. If there is no reply within the configurable time limit, the server disconnects the client.
NATS provides a text-based message format. The text-based makes it easy to implement NATS clients. The key consideration is deciding on a parsing strategy.
The NATS server implements a that is fast and efficient. Off the wire, a NATS message is simply a slice of bytes. Across the wire the message is transported as an immutable string over a TCP connection. It is up to the client to implement logic to parse the message.
The NATS message structure includes the Subject string, an optional Reply string, and an optional Data field that is a byte array. The type Msg is a structure used by Subscribers and PublishMsg().
A NATS publisher publishes the data argument to the given subject. The data argument is left untouched and needs to be correctly interpreted on the receiver. How the client parses a NATS message depends on the programming language.
Generally, protocol parsing for a NATS client is a string operation. In Python, for example, string operations are faster than regex. The Go and Java clients also use string operations to parse the message. But, if you look at the Ruby client, regex is used to parse the protocol because in Ruby regex is faster than string operations.
In sum, there is no magic formula for parsing—it depends on the programming language. But, you need to take into consideration how you are going to parse the message when you write a client.
When you make a subscription to the server, you need to store and dispatch callback handlers.
On the client side, you need a hash map for this data structure. The hash map will be storing the callback that maps the subscription ID to the subscription.
The key of the hash map is the subscription ID. The key is used to look up the callback in the hash map. When you process the NATS message off the wire, you pass the parameters subject, reply subject, and the payload to the callback handler, which does its work.
Thus, you must store the mapping of subscription ID to the callback. Inside the subscription you have the callback.
When to use pub/sub vs. req/rep depends on your use case. Run the tutorials for each to understand the differences between each style of implementation.
Considerations for error handling primarily include handling client disconnections and implementing retry logic.
The NATS client has reconnection logic. So, if you are implementing clustering, you need to implement reconnect callbacks a priori, meaning you cannot modify it during runtime. When you start it, you need to have that information already.
nats-server -DV -m 8222 -user foo -pass barnats.Connect("nats://foo:bar@localhost:4222")type Msg struct {
Subject string
Reply string
Data []byte
Sub *Subscription
}The NATS server clustering protocol describes the protocols passed between NATS servers within a cluster to share accounts, subscriptions, forward messages, and share cluster topology regarding new servers. It is a simple text-based protocol. Servers communicate with each other through a regular TCP/IP or TLS socket using a small set of protocol operations that are terminated by newline.
The NATS server implements a zero allocation byte parser that is fast and efficient.
The NATS cluster protocol is very similar to that of the NATS client protocol. In the context of a cluster, it can be helpful to visualize a server being a proxy operating on behalf of its connected clients, subscribing, unsubscribing, sending and receiving messages.
Subject names and wildcards: The NATS cluster protocol has the same features and restrictions as the client with respect to subject names and wildcards. Clients are bound to a single account, however the cluster protocol handles all accounts.
Field Delimiters: The fields of NATS protocol messages are delimited by whitespace characters '`'\(space\) or\t` (tab). Multiple whitespace characters will be treated as a single field delimiter.
Newlines: Like other text-based protocols, NATS uses CR followed by LF (CR+LF, \r, 0x0D0A) to terminate protocol messages. This newline sequence is also used to mark the beginning of the actual message payload in a RMSG protocol message.
The following table briefly describes the NATS cluster protocol messages. As in the client protocol, the NATS protocol operation names are case insensitive, thus SUB foo 1\r and sub foo 1\r are equivalent.
Click the name to see more detailed information, including syntax:
The following sections explain each protocol message.
As soon as the server accepts a connection from another server, it will send information about itself and the configuration and security requirements that are necessary for the other server to successfully authenticate with the server and exchange messages.
The connecting server also sends an INFO message. The accepting server will add an ip field containing the address and port of the connecting server, and forward the new server's INFO message to all servers it is routed to.
Any servers in a cluster receiving an INFO message with an ip field will attempt to connect to the server at that address, unless already connected. This propagation of INFO messages on behalf of a connecting server provides automatic discovery of new servers joining a cluster.
INFO {["option_name":option_value],...}
The valid options are as follows:
server_id: The unique identifier of the NATS server
version: The version of the NATS server
go: The version of golang the NATS server was built with
Below is an example of an INFO string received by a NATS server, with the ip field.
The CONNECT message is analogous to the message. Once the NATS server has established a TCP/IP socket connection with another server, and an message has been received, the server will send a CONNECT message to provide more information about the current connection as well as security information.
CONNECT {["option_name":option_value],...}
The valid options are as follows:
tls_required: Indicates whether the server requires an SSL connection.
auth_token: Authorization token
user: Connection username (if auth_required is set)
Here is an example from the default string from a server.
CONNECT {"tls_required":false,"name":"wt0vffeQyoDGMVBC2aKX0b"}\r
RS+ initiates a subscription to a subject on on a given account, optionally with a distributed queue group name and weighting factor. Note that queue subscriptions will use RS+ for increases and decreases to queue weight except when the weighting factor is 0.
Subscription: RS+ <account> <subject>\r
Queue Subscription: RS+ <account> <subject> <queue> <weight>\r
where:
account: The account associated with the subject interest
subject: The subject
queue: Optional queue group name
RS- unsubcribes from the specified subject on the given account. It is sent by a server when it no longer has interest in a given subject.
Subscription: RS- <account> <subject>\r
where:
account: The account associated with the subject interest
subject: The subject
The RMSG protocol message delivers a message to another server.
RMSG <account> <subject> [reply-to] <#bytes>\r\n[payload]\r
where:
account: The account associated with the subject interest
subject: Subject name this message was received on
reply-to: The optional reply subject
PING and PONG implement a simple keep-alive mechanism between servers. Once two servers establish a connection with each other, the NATS server will continuously send PING messages to other servers at a configurable interval. If another server fails to respond with a PONG message within the configured response interval, the server will terminate its connection. If your connection stays idle for too long, it is cut off.
If the another server sends a ping request, a server will reply with a pong message to notify the other server that it is still present.
PING\r PONG\r
The -ERR message is used by the server to indicate a protocol, authorization, or other runtime connection error to another server. Most of these errors result in the remote server closing the connection.
Origin Server
Delivers a message for a given subject and account to another server.
All Servers
PING keep-alive message
All Servers
PONG keep-alive response
All Servers
Indicates a protocol error. May cause the remote server to disconnect.
host: The host specified in the cluster parameter/options
port: The port number specified in the cluster parameter/options
auth_required: If this is set, then the server should try to authenticate upon connect.
tls_required: If this is set, then the server must authenticate using TLS.
max_payload: Maximum payload size that the server will accept.
connect_urls : A list of server urls that a client can connect to.
ip: Optional route connection address of a server, nats-route://<hostname>:<port>
pass: Connection password (if auth_required is set)
name: Generated Server Name
lang: The implementation language of the server (go).
version: The version of the server.
weight: Optional queue group weight representing how much interest/subscribers
#bytes: Size of the payload in bytes
payload: The message payload data
All Servers
Sent after initial TCP/IP connection and to update cluster knowledge
All Servers
Sent to establish a route
All Servers
Subscribes to a subject for a given account on behalf of interested clients.
All Servers
Unsubscribe (or auto-unsubscribe) from subject for a given account.
INFO {"server_id":"KP19vTlB417XElnv8kKaC5","version":"2.0.0","go":"","host":"localhost","port":5222,"auth_required":false,"tls_required":false,"tls_verify":false,"max_payload":1048576,"ip":"nats-route://127.0.0.1:5222/","connect_urls":["localhost:4222"]}The normal way to use JetStream is through the NATS client libraries which expose a set of JetStream functions that you can use directly in your programs. But that is not the only way you can interact with the JetStream infrastructure programmatically. Just like core NATS has a wire protocol on top of TCP, the JetStream enabled nats-server(s) expose a set of Services over core NATS.
All of these subjects are found as constants in the NATS Server source, so for example the subject $JS.API.STREAM.LIST is represented by api.JSApiStreamList constant in the nats-server source. Tables below will reference these constants and payload related data structures.
Note that if the resources you're trying to access have a JetStream associated with them, then the subject prefix will be $JS.{domain}.API rather than $JS.API.
The APIs used for administrative tools all respond with standardised JSON and these include errors.
Here the responses include a type which can be used to find the JSON Schema for each response.
Non-admin APIs - like those for adding a message to the stream will respond with -ERR or +OK with an optional reason after.
All of the admin actions the nats CLI can do fall in the sections below. The API structure is kept in the api package in the jsm.go repository.
Subjects that end in T like api.JSApiConsumerCreateT are formats and would need to have the Stream Name and in some cases also the Consumer name interpolated into them. In this case t := fmt.Sprintf(api.JSApiConsumerCreateT, streamName) to get the final subject.
The command nats events will show you an audit log of all API access events which includes the full content of each admin request, use this to view the structure of messages the nats command sends.
The API uses JSON for inputs and outputs, all the responses are typed using a type field which indicates their Schema. A JSON Schema repository can be found in nats-io/jsm.go/schemas.
Sourcing and mirroring streams use 3 inbound and 2 outbound subjects to establish and control the data flow. When setting permissions or creating export/import agreements all 5 subjects may need to be considered.
Notes:
There are two variants to the consumer-create subject depending on the number of filters.
In some setup a domain prefix may be present e.g. $JS.<domain>.API.CONSUMER.CREATE.<stream>.>
The stream from which data is sourced/mirrored MAY NOT be reachable. It may not have been created yet OR the route may be down. This does not prevent the source/mirror agreement from being created.
The target stream will try to create a consumer every 10s to 60s. (This value may change in the future or may be configurable). Note that delivery may therefore only resume after a short delay.
For active consumers heartbeats are sent at a rate of 1/s.
Do not delete and recreate the original stream! Please flush/purge the stream instead. The target stream remembers the last sequence id to be delivered. A delete will reset the sequence ID.
$JS.FC.<stream>.> - The flow control subject is NOT prefixed with a JetStream domain. This creates a limitation where identically named streams in different domains cannot be reliably sourced/mirrored into the same account. Please create unique stream names to avoid this limitation.
When using the subjects-based ACL, please note the patterns in the subjects grouped by purpose below.
General information
Stream Admin
Consumer Admin
Consumer message flow
Optional Events and Advisories :
This design allows you to easily create ACL rules that limit users to a specific Stream or Consumer and to specific verbs for administration purposes. For ensuring only the receiver of a message can Ack it we have response permissions ensuring you can only Publish to Response subject for messages you received.
Messages that need acknowledgment will have a Reply subject set, something like $JS.ACK.ORDERS.test.1.2.2, this is the prefix defined in api.JetStreamAckPre followed by <stream>.<consumer>.<delivered count>.<stream sequence>.<consumer sequence>.<timestamp>.<pending messages>.
JetStream and the consumer (including sourced and mirrored streams) may exchange flow control messages. A message with the header: NATS/1.0 100 FlowControl Request must be replied to, otherwise the consumer may stall. The reply subjects looks like: $JS.FC.orders.6i5h0GiQ.ep3Y
In all of the Synadia maintained API's you can simply do msg.Respond(nil) (or language equivalent) which will send nil to the reply subject.
If you have a pull-based Consumer you can send a standard NATS Request to $JS.API.CONSUMER.MSG.NEXT.<stream>.<consumer>, here the format is defined in api.JetStreamRequestNextT and requires populating using fmt.Sprintf().
Here we ask for just 1 message - nats req only shows 1 - but you can fetch a batch of messages by varying the argument. This combines well with the AckAll Ack policy.
The above request for the next message will stay in the server for as long as the client is connected and future pulls from the same client will accumulate on the server, meaning if you ask for 1 message 100 times and 1000 messages arrive you'll get sent 100 messages not 1.
This is often not desired, pull consumers support a mode where a JSON document is sent describing the pull request.
This requests 10 messages and asks the server to keep this request for 7 seconds, this is useful when you poll the server frequently and do not want the pull requests to accumulate on the server. Set the expire time to now + your poll frequency.
Here we see a second format of the Pull request that will not store the request on the queue at all but when there are no messages to deliver will send a nil bytes message with a Status header of 404, this way you can know when you reached the end of the stream for example. A 409 is returned if the Consumer has reached MaxAckPending limits.
If you know the Stream sequence of a message, you can fetch it directly, this does not support acks. Do a Request() to $JS.API.STREAM.MSG.GET.ORDERS sending it the message sequence as payload. Here the prefix is defined in api.JetStreamMsgBySeqT which also requires populating using fmt.Sprintf().
The Subject shows where the message was received, Data is base64 encoded and Time is when it was received.
Samples are published to a specific subject per Consumer, something like $JS.EVENT.METRIC.CONSUMER_ACK.<stream>.<consumer> you can subscribe to that and get api.ConsumerAckMetric messages in JSON format. The prefix is defined in api.JetStreamMetricConsumerAckPre.
$JS.API.STREAM.CREATE.*
api.JSApiStreamCreateT
Creates a new Stream
api.StreamConfig
api.JSApiStreamCreateResponse
$JS.API.STREAM.UPDATE.*
api.JSApiStreamUpdateT
Updates an existing Stream with new config
api.StreamConfig
api.JSApiStreamUpdateResponse
$JS.API.STREAM.INFO.*
api.JSApiStreamInfoT
Information about config and state of a Stream
empty payload, Stream name in subject
api.JSApiStreamInfoResponse
$JS.API.STREAM.DELETE.*
api.JSApiStreamDeleteT
Deletes a Stream and all its data
empty payload, Stream name in subject
api.JSApiStreamDeleteResponse
$JS.API.STREAM.PURGE.*
api.JSApiStreamPurgeT
Purges all of the data in a Stream, leaves the Stream
empty payload, Stream name in subject
api.JSApiStreamPurgeResponse
$JS.API.STREAM.MSG.DELETE.*
api.JSApiMsgDeleteT
Deletes a specific message in the Stream by sequence, useful for GDPR compliance
api.JSApiMsgDeleteRequest
api.JSApiMsgDeleteResponse
$JS.API.STREAM.MSG.GET.*
api.JSApiMsgGetT
Retrieves a specific message from the stream
api.JSApiMsgGetRequest
api.JSApiMsgGetResponse
$JS.API.STREAM.SNAPSHOT.*
api.JSApiStreamSnapshotT
Initiates a streaming backup of a streams data
api.JSApiStreamSnapshotRequest
api.JSApiStreamSnapshotResponse
$JS.API.STREAM.RESTORE.*
api.JSApiStreamRestoreT
Initiates a streaming restore of a stream
{}
api.JSApiStreamRestoreResponse
$JS.API.CONSUMER.CREATE.<stream>.<consumer>.<filter>
api.JSApiConsumerCreateExT
Create a consumer (server 2.9+)
api.CreateConsumerRequest
api.JSApiConsumerCreateResponse
$JS.API.CONSUMER.LIST.<stream>
api.JSApiConsumerListT
Paged list of known consumers including their current info for a given stream
api.JSApiConsumerListRequest
api.JSApiConsumerListResponse
$JS.API.CONSUMER.NAMES.<stream>
api.JSApiConsumerNamesT
Paged list of known consumer names for a given stream
api.JSApiConsumerNamesRequest
api.JSApiConsumerNamesResponse
$JS.API.CONSUMER.INFO.<stream>.<consumer>
api.JSApiConsumerInfoT
Information about a specific consumer by name
empty payload
api.JSApiConsumerInfoResponse
$JS.API.CONSUMER.DELETE.<stream>.<consumer>
api.JSApiConsumerDeleteT
Deletes a Consumer
empty payload
api.JSApiConsumerDeleteResponse
$JS.FC.<stream>.>
N/A
Consumer to subscriber flow control replies for PUSH consumer. Also used for sourcing and mirroring, which are implemented as PUSH consumers. If this subject is not forwarded, the consumer my stall under high load.
empty payload
N/A
$JSC.R.<uid>
N/A
Reply subject used by source and mirror consumer create request
Consumer info
N/A
$JS.S.<uid>
N/A
Default delivery subject for sourced streams. Can be overwritten by the deliver attribute in the source configuration.
Message data
N/A
$JS.M.<uid>
N/A
Default delivery subject for mirroed streams. Can be overwritten by the deliver attribute in the source configuration.
Message data
N/A
$JS.ACK.<stream>.>
N/A
Acknowledgments for PULL consumers. When this subject is not forwarded, PULL consumers in acknowledgment modes all or explicit will fail.
empty payload
reply subject
$JS.S.<uid> (source) OR $JS.M.<uid> (mirror) OR <custom deliver subject>
inbound
Message data and heartbeats
message stream
$JS.API.INFO
api.JSApiAccountInfo
Retrieves stats and limits about your account
empty payload
api.JetStreamAccountStats
$JS.API.STREAM.LIST
api.JSApiStreamList
Paged list known Streams including all their current information
api.JSApiStreamListRequest
api.JSApiStreamListResponse
$JS.API.STREAM.NAMES
api.JSApiStreamNames
Paged list of Streams
api.JSApiStreamNamesRequest
api.JSApiStreamNamesResponse
$JS.API.CONSUMER.CREATE.<stream>
api.JSApiConsumerCreateT
Create an ephemeral consumer
api.ConsumerConfig
api.JSApiConsumerCreateResponse
$JS.API.CONSUMER.DURABLE.CREATE.<stream>.<consumer>
api.JSApiDurableCreateT
Create a consumer
api.ConsumerConfig
api.JSApiConsumerCreateResponse
$JS.API.CONSUMER.CREATE.<stream>.> and/or $JS.API.CONSUMER.CREATE.<stream>
outbound
Create an ephemeral consumer to deliver pending messages. Note that this subject may be prefixed with a JetStream domain $JS.<domain>.API.CONSUMER.CREATE.<stream>.<consumer>.
The consumer create comes in 2 flavors depending on the number of filter subjects:
* $JS.API.CONSUMER.CREATE.<stream> - When there is no filter or there are multiple filters.
* $JS.API.CONSUMER.CREATE.<stream>.<consumer>.<filter subject> - When there is exactly one filter subject
service request with $JSC.R.<uid> as reply subject
$JS.FC.<stream>.>
outbound
Flow control messages. Will on slow routes or when the target cannot keep up with the message flow.
service request with $JSC.R.<uid> as reply subject
$JSC.R.<uid>
inbound
Reply to consumer creation request
reply message to service request
nats req '$JS.API.STREAM.INFO.nonexisting' ''Published 11 bytes to $JS.API.STREAM.INFO.nonexisting
Received [_INBOX.lcWgjX2WgJLxqepU0K9pNf.mpBW9tHK] : {
"type": "io.nats.jetstream.api.v1.stream_info_response",
"error": {
"code": 404,
"description": "stream not found"
}
}nats req '$JS.STREAM.INFO.ORDERS' ''Published 6 bytes to $JS.STREAM.INFO.ORDERS
Received [_INBOX.fwqdpoWtG8XFXHKfqhQDVA.vBecyWmF] : '{
"type": "io.nats.jetstream.api.v1.stream_info_response",
"config": {
"name": "ORDERS",
...
}$JS.API.INFO$JS.API.STREAM.CREATE.<stream>
$JS.API.STREAM.UPDATE.<stream>
$JS.API.STREAM.DELETE.<stream>
$JS.API.STREAM.INFO.<stream>
$JS.API.STREAM.PURGE.<stream>
$JS.API.STREAM.LIST
$JS.API.STREAM.NAMES
$JS.API.STREAM.MSG.DELETE.<stream>
$JS.API.STREAM.MSG.GET.<stream>
$JS.API.STREAM.SNAPSHOT.<stream>
$JS.API.STREAM.RESTORE.<stream>$JS.API.CONSUMER.CREATE.<stream>
$JS.API.CONSUMER.DURABLE.CREATE.<stream>.<consumer>
$JS.API.CONSUMER.DELETE.<stream>.<consumer>
$JS.API.CONSUMER.INFO.<stream>.<consumer>
$JS.API.CONSUMER.LIST.<stream>
$JS.API.CONSUMER.NAMES.<stream>$JS.API.CONSUMER.MSG.NEXT.<stream>.<consumer>
$JS.SNAPSHOT.RESTORE.<stream>.<msg id>
$JS.ACK.<stream>.<consumer>.x.x.x
$JS.SNAPSHOT.ACK.<stream>.<msg id>
$JS.FC.<stream>.>$JS.EVENT.METRIC.CONSUMER_ACK.<stream>.<consumer>
$JS.EVENT.ADVISORY.CONSUMER.MAX_DELIVERIES.<stream>.<consumer>
$JS.EVENT.ADVISORY.CONSUMER.MSG_TERMINATED.<stream>.<consumer>
$JS.EVENT.ADVISORY.STREAM.CREATED.<stream>
$JS.EVENT.ADVISORY.STREAM.DELETED.<stream>
$JS.EVENT.ADVISORY.STREAM.UPDATED.<stream>
$JS.EVENT.ADVISORY.CONSUMER.CREATED.<stream>.<consumer>
$JS.EVENT.ADVISORY.CONSUMER.DELETED.<stream>.<consumer>
$JS.EVENT.ADVISORY.STREAM.SNAPSHOT_CREATE.<stream>
$JS.EVENT.ADVISORY.STREAM.SNAPSHOT_COMPLETE.<stream>
$JS.EVENT.ADVISORY.STREAM.RESTORE_CREATE.<stream>
$JS.EVENT.ADVISORY.STREAM.RESTORE_COMPLETE.<stream>
$JS.EVENT.ADVISORY.STREAM.LEADER_ELECTED.<stream>
$JS.EVENT.ADVISORY.STREAM.QUORUM_LOST.<stream>
$JS.EVENT.ADVISORY.CONSUMER.LEADER_ELECTED.<stream>.<consumer>
$JS.EVENT.ADVISORY.CONSUMER.QUORUM_LOST.<stream>.<consumer>
$JS.EVENT.ADVISORY.APInats req '$JS.API.CONSUMER.MSG.NEXT.ORDERS.test' '1'Published 1 bytes to $JS.API.CONSUMER.MSG.NEXT.ORDERS.test
Received [js.1] : 'message 1'{
"expires": 7000000000,
"batch": 10
}{
"batch": 10,
"no_wait": true
}nats req '$JS.API.CONSUMER.MSG.NEXT.ORDERS.NEW' '{"no_wait": true, "batch": 10}'13:45:30 Sending request on "$JS.API.CONSUMER.MSG.NEXT.ORDERS.NEW"
13:45:30 Received on "_INBOX.UKQGqq0W1EKl8inzXU1naH.XJiawTRM" rtt 594.908µs
13:45:30 Status: 404
13:45:30 Description: No Messagesnats req '$JS.API.STREAM.MSG.GET.ORDERS' '{"seq": 1}'Published 1 bytes to $JS.STREAM.ORDERS.MSG.BYSEQ
Received [_INBOX.cJrbzPJfZrq8NrFm1DsZuH.k91Gb4xM] : '{
"type": "io.nats.jetstream.api.v1.stream_msg_get_response",
"message": {
"subject": "x",
"seq": 1,
"data": "aGVsbG8=",
"time": "2020-05-06T13:18:58.115424+02:00"
}
}'The wire protocol used to communicate between the NATS server and clients is a simple, text-based publish/subscribe style protocol. Clients connect to and communicate with nats-server (the NATS server) through a regular TCP/IP socket using a small set of protocol operations that are terminated by a new line.
Unlike traditional messaging systems that use a binary message format that require an API to consume, the text-based NATS protocol makes it easy to implement clients in a wide variety of programming and scripting languages. In fact, refer to the topic NATS Protocol Demo to play with the NATS protocol for yourself using telnet.
The NATS server implements a zero allocation byte parser that is fast and efficient.
Control Line with Optional Content: Each interaction between the client and server consists of a control, or protocol, line of text followed, optionally by message content. Most of the protocol messages don't require content, only PUB, MSG, HPUB, and HMSG include payloads.
Field Delimiters: The fields of NATS protocol messages are delimited by whitespace characters (space) or (tab). Multiple whitespace characters will be treated as a single field delimiter.
Newlines: NATS uses ␍ followed by ␊ (␍␊, 0x0D0A) to terminate protocol messages. This newline sequence is also used to mark the end of the message payload in PUB, MSG, HPUB, and HMSG protocol messages.
Subject names: Subject names, including reply subject names, are case-sensitive and must be non-empty alphanumeric strings with no embedded whitespace. All UTF-8 characters except spaces/tabs and separators which are . and > are allowed. Subject names can be optionally token-delimited using the dot character (.), e.g.:
FOO, BAR, foo.bar, foo.BAR, FOO.BAR and FOO.BAR.BAZ are all valid subject names
FOO. BAR, foo. .bar andfoo..bar are not valid subject names
A subject is comprised of 1 or more tokens. Tokens are separated by . and can be any non whitespace UTF-8 character. The full wildcard token > is only valid as the last token and matches all tokens past that point. A token wildcard, * matches any token in the position it was listed. Wildcard tokens should only be used in a wildcard capacity and not part of a literal token.
Character Encoding: Subject names should be UTF-8 compatible.
Wildcards: NATS supports the use of wildcards in subject subscriptions.
The asterisk character (*) matches a single token at any level of the subject.
The greater than symbol (>), also known as the full wildcard, matches one or more tokens at the tail of a subject, and must be the last token. The wildcarded subject foo.> will match foo.bar or foo.bar.baz.1, but not foo.
For example, the wildcard subscriptions foo.*.quux and foo.> both match foo.bar.quux, but only the latter matches foo.bar.baz. With the full wildcard, it is also possible to express interest in every subject that may exist in NATS: sub > 1, limited of course by authorization settings.
The following table briefly describes the NATS protocol messages. NATS protocol operation names are case insensitive, thus SUB foo 1␍␊ and sub foo 1␍␊ are equivalent.
Click the name to see more detailed information, including syntax:
The following sections explain each protocol message.
A client will need to start as a plain TCP connection, then when the server accepts a connection from the client, it will send information about itself, the configuration and security requirements necessary for the client to successfully authenticate with the server and exchange messages.
When using the updated client protocol (see below), INFO messages can be sent anytime by the server. This means clients with that protocol level need to be able to asynchronously handle INFO messages.
INFO {"option_name":option_value,...}␍␊
The valid options are as follows, encoded as JSON:
The connect_urls field is a list of urls the server may send when a client first connects, and when there are changes to server cluster topology. This field is considered optional, and may be omitted based on server configuration and client protocol level.
When a NATS server cluster expands, an INFO message is sent to the client with an updated connect_urls list. This cloud-friendly feature asynchronously notifies a client of known servers, allowing it to connect to servers not originally configured.
The connect_urls will contain a list of strings with an IP and port, looking like this: "connect_urls":["10.0.0.184:4333","192.168.129.1:4333","192.168.192.1:4333"]
Below you can see a sample connection string from a telnet connection to the demo.nats.io site.
The CONNECT message is the client version of the message. Once the client has established a TCP/IP socket connection with the NATS server, and an message has been received from the server, the client may send a CONNECT message to the NATS server to provide more information about the current connection as well as security information.
CONNECT {"option_name":option_value,...}␍␊
The valid options are as follows, encoded as JSON:
Here is an example from the default string of the Go client:
Most clients set verbose to false by default. This means that the server should not confirm each message it receives on this connection with a back to the client.
The PUB message publishes the message payload to the given subject name, optionally supplying a reply subject. If a reply subject is supplied, it will be delivered to eligible subscribers along with the supplied payload. Note that the payload itself is optional. To omit the payload, set the payload size to 0, but the second CRLF is still required.
PUB <subject> [reply-to] <#bytes>␍␊[payload]␍␊
where:
To publish the ASCII string message payload "Hello NATS!" to subject FOO:
PUB FOO 11␍␊Hello NATS!␍␊
To publish a request message "Knock Knock" to subject FRONT.DOOR with reply subject JOKE.22:
PUB FRONT.DOOR JOKE.22 11␍␊Knock Knock␍␊
To publish an empty message to subject NOTIFY:
PUB NOTIFY 0␍␊␍␊
The HPUB message is the same as PUB but extends the message payload to include NATS headers. Note that the payload itself is optional. To omit the payload, set the total message size equal to the size of the headers. Note that the trailing CR+LF is still required.
NATS headers are similar, in structure and semantics, to HTTP headers as name: value pairs including supporting multi-value headers. Headers can be mixed case and NATS will preserve case between message publisher and message receiver(s). See also .
HPUB <subject> [reply-to] <#header bytes> <#total bytes>␍␊[headers]␍␊␍␊[payload]␍␊
where:
To publish the ASCII string message payload "Hello NATS!" to subject FOO with one header Bar with value Baz:
HPUB FOO 22 33␍␊NATS/1.0␍␊Bar: Baz␍␊␍␊Hello NATS!␍␊
To publish a request message "Knock Knock" to subject FRONT.DOOR with reply subject JOKE.22 and two headers:
HPUB FRONT.DOOR JOKE.22 45 56␍␊NATS/1.0␍␊BREAKFAST: donut␍␊LUNCH: burger␍␊␍␊Knock Knock␍␊
To publish an empty message to subject NOTIFY with one header Bar with value Baz:
HPUB NOTIFY 22 22␍␊NATS/1.0␍␊Bar: Baz␍␊␍␊␍␊
To publish a message to subject MORNING MENU with one header BREAKFAST having two values and payload "Yum!"
HPUB MORNING.MENU 47 51␍␊NATS/1.0␍␊BREAKFAST: donut␍␊BREAKFAST: eggs␍␊␍␊Yum!␍␊
SUB initiates a subscription to a subject, optionally joining a distributed queue group.
SUB <subject> [queue group] <sid>␍␊
where:
To subscribe to the subject FOO with the connection-unique subscription identifier (sid) 1:
SUB FOO 1␍␊
To subscribe the current connection to the subject BAR as part of distribution queue group G1 with sid 44:
SUB BAR G1 44␍␊
UNSUB unsubscribes the connection from the specified subject, or auto-unsubscribes after the specified number of messages has been received.
UNSUB <sid> [max_msgs]␍␊
where:
The following examples concern subject FOO which has been assigned sid 1. To unsubscribe from FOO:
UNSUB 1␍␊
To auto-unsubscribe from FOO after 5 messages have been received:
UNSUB 1 5␍␊
The MSG protocol message is used to deliver an application message to the client.
MSG <subject> <sid> [reply-to] <#bytes>␍␊[payload]␍␊
where:
The following message delivers an application message from subject FOO.BAR:
MSG FOO.BAR 9 11␍␊Hello World␍␊
To deliver the same message along with a reply subject:
MSG FOO.BAR 9 GREETING.34 11␍␊Hello World␍␊
The HMSG message is the same as MSG, but extends the message payload with headers. See also .
HMSG <subject> <sid> [reply-to] <#header bytes> <#total bytes>␍␊[headers]␍␊␍␊[payload]␍␊
where:
The following message delivers an application message from subject FOO.BAR with a header:
HMSG FOO.BAR 34 45␍␊NATS/1.0␍␊FoodGroup: vegetable␍␊␍␊Hello World␍␊
To deliver the same message along with a reply subject:
HMSG FOO.BAR 9 BAZ.69 34 45␍␊NATS/1.0␍␊FoodGroup: vegetable␍␊␍␊Hello World␍␊
PING and PONG implement a simple keep-alive mechanism between client and server. Once a client establishes a connection to the NATS server, the server will continuously send PING messages to the client at a configurable interval. If the client fails to respond with a PONG message within the configured response interval, the server will terminate its connection. If your connection stays idle for too long, it is cut off.
If the server sends a ping request, you can reply with a pong message to notify the server that you are still interested. You can also ping the server and will receive a pong reply. The ping/pong interval is configurable.
The server uses normal traffic as a ping/pong proxy, so a client that has messages flowing may not receive a ping from the server.
PING␍␊
PONG␍␊
The following example shows the demo server pinging the client and finally shutting it down.
When the verbose connection option is set to true (the default value), the server acknowledges each well-formed protocol message from the client with a +OK message. Most NATS clients set the verbose option to false using the message
The -ERR message is used by the server indicate a protocol, authorization, or other runtime connection error to the client. Most of these errors result in the server closing the connection.
Handling of these errors usually has to be done asynchronously.
+OK␍␊
-ERR <error message>␍␊
Some protocol errors result in the server closing the connection. Upon receiving these errors, the connection is no longer valid and the client should clean up relevant resources. These errors include:
-ERR 'Unknown Protocol Operation': Unknown protocol error
-ERR 'Attempted To Connect To Route Port': Client attempted to connect to a route port instead of the client port
-ERR 'Authorization Violation': Client failed to authenticate to the server with credentials specified in the message
Protocol error messages where the connection remains open are listed below. The client should not close the connection in these cases.
-ERR 'Invalid Subject': Client sent a malformed subject (e.g. sub foo. 90)
-ERR 'Permissions Violation for Subscription to <subject>': The user specified in the message does not have permission to subscribe to the subject.
-ERR 'Permissions Violation for Publish to <subject>'
Wildcards must be a separate token (foo.*.baz or foo.> are syntactically valid; foo*.bar, f*o.b*r and foo> are not)
Client
Subscribe to a subject (or subject wildcard)
Client
Unsubscribe (or auto-unsubscribe) from subject
Server
Delivers a message payload to a subscriber
Server
Delivers a message payload to a subscriber with NATS headers
Both
PING keep-alive message
Both
PONG keep-alive response
Server
Acknowledges well-formed protocol message in verbose mode
Server
Indicates a protocol error. May cause client disconnect.
go
The version of golang the NATS server was built with.
string
always
host
The IP address used to start the NATS server, by default this will be 0.0.0.0 and can be configured with -client_advertise host:port.
string
always
port
The port number the NATS server is configured to listen on.
int
always
headers
Whether the server supports headers.
bool
always
max_payload
Maximum payload size, in bytes, that the server will accept from the client.
int
always
proto
An integer indicating the protocol version of the server. The server version 1.2.0 sets this to 1 to indicate that it supports the "Echo" feature.
int
always
client_id
The internal client identifier in the server. This can be used to filter client connections in monitoring, correlate with error logs, etc...
uint64
optional
auth_required
If this is true, then the client should try to authenticate upon connect.
bool
optional
tls_required
If this is true, then the client must perform the TLS/1.2 handshake. Note, this used to be ssl_required and has been updated along with the protocol from SSL to TLS.
bool
optional
tls_verify
If this is true, the client must provide a valid certificate during the TLS handshake.
bool
optional
tls_available
If this is true, the client can provide a valid certificate during the TLS handshake.
bool
optional
connect_urls
List of server urls that a client can connect to.
[string]
optional
ws_connect_urls
List of server urls that a websocket client can connect to.
[string]
optional
ldm
If the server supports Lame Duck Mode notifications, and the current server has transitioned to lame duck, ldm will be set to true.
bool
optional
git_commit
The git hash at which the NATS server was built.
string
optional
jetstream
Whether the server supports JetStream.
bool
optional
ip
The IP of the server.
string
optional
client_ip
The IP of the client.
string
optional
nonce
The nonce for use in CONNECT.
string
optional
cluster
The name of the cluster.
string
optional
domain
The configured NATS domain of the server.
string
optional
auth_token
Client authorization token.
string
if auth_required is true
user
Connection username.
string
if auth_required is true
pass
Connection password.
string
if auth_required is true
name
Client name.
string
false
lang
The implementation language of the client.
string
true
version
The version of the client.
string
true
protocol
Sending 0 (or absent) indicates client supports original protocol. Sending 1 indicates that the client supports dynamic reconfiguration of cluster topology changes by asynchronously receiving messages with known servers it can reconnect to.
int
false
echo
If set to false, the server (version 1.2.0+) will not send originating messages from this connection to its own subscriptions. Clients should set this to false only for server supporting this feature, which is when proto in the INFO protocol is set to at least 1.
bool
false
sig
In case the server has responded with a nonce on INFO, then a NATS client must use this field to reply with the signed nonce.
string
if nonce received
jwt
The JWT that identifies a user permissions and account.
string
false
no_responders
Enable .
bool
false
headers
Whether the client supports headers.
bool
false
nkey
The public NKey to authenticate the client. This will be used to verify the signature (sig) against the nonce provided in the INFO message.
string
false
payload
The message payload data.
string
false
#total bytes
The total size of headers and payload sections in bytes.
int
true
headers
Header version NATS/1.0␍␊ followed by one or more name: value pairs, each separated by ␍␊.
string
false
payload
The message payload data.
string
false
#bytes
Size of the payload in bytes.
int
always
payload
The message payload data.
string
optional
#header bytes
The size of the headers section in bytes including the ␍␊␍␊ delimiter before the payload.
int
always
#total bytes
The total size of headers and payload sections in bytes.
int
always
headers
Header version NATS/1.0␍␊ followed by one or more name: value pairs, each separated by ␍␊.
string
optional
payload
The message payload data.
string
optional
-ERR 'Authorization Timeout': Client took too long to authenticate to the server after establishing a connection (default 1 second)
-ERR 'Invalid Client Protocol': Client specified an invalid protocol version in the CONNECT message
-ERR 'Maximum Control Line Exceeded': Message destination subject and reply subject length exceeded the maximum control line value specified by the max_control_line server option. The default is 1024 bytes.
-ERR 'Parser Error': Cannot parse the protocol message sent by the client
-ERR 'Secure Connection - TLS Required': The server requires TLS and the client does not have TLS enabled.
-ERR 'Stale Connection': The server hasn't received a message from the client, including a PONG in too long.
-ERR 'Maximum Connections Exceeded': This error is sent by the server when creating a new connection and the server has exceeded the maximum number of connections specified by the max_connections server option. The default is 64k.
-ERR 'Slow Consumer': The server pending data size for the connection has reached the maximum size (default 10MB).
-ERR 'Maximum Payload Violation': Client attempted to publish a message with a payload size that exceeds the max_payload size configured on the server. This value is supplied to the client upon connection in the initial INFO message. The client is expected to do proper accounting of byte size to be sent to the server in order to handle this error synchronously.
Server
Sent to client after initial TCP/IP connection
Client
Sent to server to specify connection information
Client
Publish a message to a subject, with optional reply subject
Client
server_id
The unique identifier of the NATS server.
string
always
server_name
The name of the NATS server.
string
always
version
The version of NATS.
string
verbose
Turns on +OK protocol acknowledgements.
bool
true
pedantic
Turns on additional strict format checking, e.g. for properly formed subjects.
bool
true
tls_required
Indicates whether the client requires an SSL connection.
bool
subject
The destination subject to publish to.
string
true
reply-to
The reply subject that subscribers can use to send a response back to the publisher/requestor.
string
false
#bytes
The payload size in bytes.
int
subject
The destination subject to publish to.
string
true
reply-to
The reply subject that subscribers can use to send a response back to the publisher/requestor.
string
false
#header bytes
The size of the headers section in bytes including the ␍␊␍␊ delimiter before the payload.
int
subject
The subject name to subscribe to.
string
true
queue group
If specified, the subscriber will join this queue group.
string
false
sid
A unique alphanumeric subscription ID, generated by the client.
string
sid
The unique alphanumeric subscription ID of the subject to unsubscribe from.
string
true
max_msgs
A number of messages to wait for before automatically unsubscribing.
int
false
subject
Subject name this message was received on.
string
always
sid
The unique alphanumeric subscription ID of the subject.
string
always
reply-to
The subject on which the publisher is listening for responses.
string
subject
Subject name this message was received on.
string
always
sid
The unique alphanumeric subscription ID of the subject.
string
always
reply-to
The subject on which the publisher is listening for responses.
string
Publish a message to a subject including NATS headers, with optional reply subject
always
true
true
true
true
optional
optional
telnet demo.nats.io 4222Trying 107.170.221.32...
Connected to demo.nats.io.
Escape character is '^]'.
INFO {"server_id":"Zk0GQ3JBSrg3oyxCRRlE09","version":"1.2.0","proto":1,"go":"go1.10.3","host":"0.0.0.0","port":4222,"max_payload":1048576,"client_id":2392}CONNECT {"verbose":false,"pedantic":false,"tls_required":false,"name":"","lang":"go","version":"1.2.2","protocol":1}␍␊telnet demo.nats.io 4222
Trying 107.170.221.32...
Connected to demo.nats.io.
Escape character is '^]'.
INFO {"server_id":"Zk0GQ3JBSrg3oyxCRRlE09","version":"1.2.0","proto":1,"go":"go1.10.3","host":"0.0.0.0","port":4222,"max_payload":1048576,"client_id":2392}
PING
PING
-ERR 'Stale Connection'
Connection closed by foreign host.