Skip to main content

NATS

NATS uses a plain-text protocol over TCP. Each message is a verb, optional arguments, and a CRLF; payloads follow their header line and are themselves CRLF-terminated.

Protocol Operations

OperationSent ByFormatPurpose
INFOServerINFO {json}\r\nServer details, sent on connect
CONNECTClientCONNECT {json}\r\nClient options and credentials
PUBClientPUB <subject> [reply-to] <size>\r\n<payload>\r\nPublish a message
HPUBClientHPUB <subject> [reply-to] <hdr-size> <total-size>\r\n<headers>\r\n<payload>\r\nPublish with headers
SUBClientSUB <subject> [queue-group] <sid>\r\nSubscribe to a subject
UNSUBClientUNSUB <sid> [max-msgs]\r\nUnsubscribe, optionally after a count
MSGServerMSG <subject> <sid> [reply-to] <size>\r\n<payload>\r\nDeliver a message
HMSGServerHMSG <subject> <sid> [reply-to] <hdr-size> <total-size>\r\n<headers>\r\n<payload>\r\nDeliver with headers
PINGBothPING\r\nKeepalive request
PONGBothPONG\r\nKeepalive response
+OKServer+OK\r\nAcknowledgment, when verbose is set
-ERRServer-ERR <reason>\r\nProtocol error. The server closes the connection after most of these

Subjects and Wildcards

Subjects are dot-separated tokens. Two wildcards are available when subscribing:

WildcardMatchesExample
*Exactly one tokenlogs.*.error matches logs.auth.error
>One or more tokens, and only as the final tokenlogs.> matches logs.auth and logs.auth.error

The optional queue-group argument on SUB places subscribers into a group, and the server delivers each message to only one member—this is how load is distributed across consumers.

The CONNECT Message

Credentials travel in the JSON payload of CONNECT, which is why the wire carries no distinct authentication verb.

FieldDescription
user, passUsername and password
auth_tokenToken authentication
jwtUser JWT for account-scoped authentication
sigSignature over the server's nonce, for NKey and JWT authentication
nkeyThe NKey public key
nameClient name
headersWhether the client understands HPUB and HMSG
verboseWhether the server should send +OK

JetStream

JetStream is the persistence layer, and it is not a separate protocol. Its operations are ordinary request-reply exchanges over core NATS: a client publishes a JSON request to a subject under $JS.API.> and receives a JSON reply on an inbox subject. Message acknowledgment likewise publishes to the reply subject carried on the delivery.

This matters when reading the operations table above: a JetStream consumer still uses PUB, SUB and MSG on the wire.