NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #4361 most downloaded on pub.dev
A Dart client for the NATS messaging system. Design to use with Dart and flutter.
Last release 5 days ago
03 Oct 2026
Ships unpredictably
gaps range from 8 days to 1.6 years
Most releases are documented
notes for 53 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
7 years old
63 releases · first in 2019
Add NatsConnectionLost , a NatsException thrown by Client.request() when the connection cannot carry the request. It names the request's subject and s
NatsConnectionLost, a NatsException thrown by Client.request() when the connection cannot carry the request. It names the request's subject and says whether it was sent: false when the client was not connected and the request never left, true when it was published and the connection dropped before the reply. Both cases were a plain NatsException told apart only by message text; the messages are unchanged.Client.pendingRequestCount, the number of requests waiting for a reply.request() call. Such a request now fails with sent: false, since nothing left the client.Client.request() runs requests concurrently. It used to hold one lock from publish until reply or timeout, so a single request nobody answered blocked
One column per quarter.
Client.request() runs requests concurrently. It used to hold one lock from publish until reply or timeout, so a single request nobody answered blocked every other request on the client for its full timeout. Each request now waits on its own reply inbox. The mutex dependency is gone.-ERR reaches onError as a subclass of NatsException where the client recognises it: NatsPermissionsViolation (with operation, subject and queue), NatsAuthenticationException and its subtypes NatsAuthorizationViolation and NatsAuthenticationExpired, NatsStaleConnection, NatsMaxConnectionsExceeded and NatsMaxPayloadViolation. message still holds the server's text, and NatsException.fromServerError() does the mapping.NatsPermissionsViolation, instead of waiting out its timeout for a reply that cannot come.ConnectOption.noResponders (off by default). On such a connection a request to a subject nobody is subscribed to fails immediately with NatsNoRespondersException instead of timing out. Header gains description beside status.Client.onLateReply, called with the request's subject and the delay when a reply arrives after its request timed out, so "the reply was late" can be told from "the reply never came".Client.authTokenHandler, called for the token on the first connect and on every reconnect, for tokens that expire. It may be asynchronous; a handler that throws is a failed attempt and is retried.connect(timeout: ...) now bounds the WebSocket open on ws:// and wss://. A peer that accepted the connection and never completed the upgrade used to hang the attempt for good.ping(timeout: ...), which fails with a TimeoutException when no PONG arrives in time, and connect(pingTimeout: ...), which counts an unanswered heartbeat PING at its own deadline instead of at a later tick, so a silently dead connection is noticed sooner.await it.NatsException instead of at its timeout.ws:// or wss:// open that hangs fails after timeout seconds instead of never.noResponders, onLateReply, authTokenHandler and pingTimeout change nothing unless set.A connect attempt now counts as successful only once the handshake completes (TLS upgrade, CONNECT and the first PONG), not as soon as the TCP or WebS
A connect attempt now counts as successful only once the handshake completes (TLS upgrade, CONNECT and the first PONG), not as soon as the TCP or WebSocket connection is open (#56). Previously, a failure after the socket opened (a TLS certificate that does not verify, -ERR such as maximum connections exceeded, a server closing the connection or never sending INFO):
retry: true, and connect() failed with a generic Connection closed or disconnected error;retryInterval and retryCount. Against a server whose certificate fails verification this meant thousands of connections per second.Such failures are now ordinary failed attempts: reported through onError with the real cause, counted toward retryCount and spaced by retryInterval. connect(timeout: ...) now also bounds the handshake, so a server that accepts the connection but never sends INFO no longer hangs the client.
Behavior changes:
retry: true, connect() keeps retrying through handshake failures instead of failing on the first one. With retryCount: -1 it waits until a connection succeeds.Status.disconnected or calls onDisconnect; the attempt is retried instead.Many thanks to contributor @amalic for the detailed report.
Fix a tls:// client never reconnecting after the server closed an established connection, for example on a nats-server restart ( #55 ). The client kep
tls:// client never reconnecting after the server closed an established connection, for example on a nats-server restart (#55). The client kept a reference to the dead secure socket, and the next attempt's TCP listener only forwards data while there is none, so the new server's INFO was dropped and the TLS upgrade never started. The client looped through TCP connects that the server closed with TLS Handshake Failure. Every connect attempt now starts with no references to the previous connection. This also affects nats:// connections to a server that requires TLS.connect() call changing the live connection. connect() applied its arguments (server pool, retry settings, a new connect completer) before checking whether the client was already in use, so a call that then threw client in use still swapped in its servers and retry settings, and its orphaned completer later failed as an unhandled zone error.TlsException after reporting it through onError, and an exception thrown from a stream handler has no caller to reach. The library also no longer prints socket errors to stdout; they are reported through onError only.Fix a failed socket write escaping as an unhandled zone error when the peer aborts the connection. Socket is an IOSink , so add() reports a write fail
Socket is an IOSink, so add() reports a write failure asynchronously on done instead of throwing -- the try/catch around the write never saw it and nothing was listening for it, so a keepalive ping landing on an already-aborted socket had no handler anywhere. Write failures now take the same path a read error does, onError followed by a disconnected status, on the nats:, tls:, and secure transports. On tls:// such a failure previously reached the application as nothing at all beyond a bare status change.Fix heartbeat pings raising an unhandled zone error on every disconnect. The PONG-tracking callback added in 1.3.0 used an expression body, so type in
then<int> and the null-returning onError handler could not satisfy FutureOr<int> -- visible on the Dart VM and dart2wasm (dart2js elides the cast).Bump actions/checkout / actions/cache in CI to versions that don't trigger GitHub's Node 20 deprecation warning.
JsStream.purge()/JetStream.purgeStream() now accept optional filter, keep, and seq parameters ($JS.API.STREAM.PURGE's own options), instead of only supporting an all-or-nothing purge.ObjectStore.putStream()/getStream() for uploading/downloading objects as a Stream<List<int>>/Stream<Uint8List> without buffering the whole payload in memory, computing the SHA-256 digest incrementally as chunks arrive.ObjectStore.put()/putStream() leaving a previous object's chunks orphaned in the backing stream when overwriting an existing name -- the old version's chunks are now purged once the new version is safely written.actions/checkout/actions/cache in CI to versions that don't trigger GitHub's Node 20 deprecation warning.Add consumer pause/resume support (NATS 2.11+): JetStream.pauseConsumer(stream, consumer, pauseUntil) and JetStream.resumeConsumer(stream, consumer) ,
JetStream.pauseConsumer(stream, consumer, pauseUntil) and JetStream.resumeConsumer(stream, consumer), calling $JS.API.CONSUMER.PAUSE. ConsumerInfo also gains paused/pauseUntil fields reflecting the consumer's current pause state.pub.dev publishing on tagged releases.pingInterval/maxPingsOut) never confirming a PONG reply actually arrived before counting toward the missed-ping limit, so a connection that was responding perfectly fine still got force-disconnected after maxPingsOut heartbeat ticks. The periodic heartbeat now tracks its PONG the same way Client.ping() does and resets the missed-ping counter on receipt.Update package homepage and repository URLs to point to the new dart-nats GitHub organization.
dart-nats GitHub organization.Fix background reconnection loop getting stuck or stopping prematurely after network loss by evaluating connection and closed states more robustly.
onReconnect correctly fires during a reconnection cycle instead of onConnect.Fix JetStream.listStreams()/listConsumers() silently truncating at the server's page size (256 items) instead of paginating via offset/total — account
JetStream.listStreams()/listConsumers() silently truncating at the server's page size (256 items) instead of paginating via offset/total — accounts with more streams/consumers than that lost visibility into everything past the first page, with no error or truncation flag.Consumer.messages()'s pull loop and OrderedConsumer swallowing every delivery failure into a silent retry loop instead of surfacing it through the stream's addError. For pull consumers specifically, a deleted server-side consumer never actually threw from fetch() — it silently timed out with an empty batch, indistinguishable from a merely idle consumer — so the loop now also confirms the consumer still exists whenever a batch comes back empty.KeyValue.watch()/history()/keys() leaking their ephemeral push consumer on every call — the Consumer returned by createConsumer() was discarded and never deleted once the caller cancelled or the call finished. ConsumerConfig also gains an inactiveThreshold field (serialized as inactive_threshold, same convention as idleHeartbeat) so ephemeral consumers can be given a server-side reap window as a safety net.Message.nakSync()/termSync()/inProgressSync(), awaitable twins of the existing ackSync() for nak()/term()/inProgress(). The originals call pub() without awaiting its own Future<bool>, so a disconnected client still reports success even though the ack/nak/term never reached the server — prefer the *Sync variants when that needs to be known.Update README.md with Microservices Framework (ADR-32) and Client Discovery documentation.
Add heartbeats, clustering, robust reconnection, buffer limits, pull flow control, and NATS Microservices Framework (ADR-32).
addService/MicroService hosting side:
Client.discoverServices(), getServicesInfo(), and getServicesStats() fan a request out to $SRV.* (optionally scoped to service name and ID) and collect all replies within a bounded timeout window.PingResponse, InfoResponse, EndpointInfo, StatsResponse, and EndpointStatsInfo to parse standard response payloads.Fix JetStream.accountInfo() returning all-zero Tier for single-tier accounts by parsing usage fields from the top-level response instead of a nonexist
JetStream.accountInfo() returning all-zero Tier for single-tier accounts by parsing usage fields from the top-level response instead of a nonexistent nested tier key. Also fix Tier.fromJson crash on uint64 sentinel values by reading fields as num. Thanks @nverbeek for the contribution.Fix defect #42: Ensure newInbox always appends a dot suffix (.) to inboxPrefix to conform to hierarchical NATS subject structures (_INBOX.> gateway ca
newInbox always appends a dot suffix (.) to inboxPrefix to conform to hierarchical NATS subject structures (_INBOX.> gateway callout authorization policy)...) if the prefix argument already ends with a dot.Add JetStream, Key-Value, and Object Store API enhancements and handle-based classes:
JsStream class wrapping JetStream stream operations (info, purge, consumer, createConsumer).Consumer<T> class with fetch (for pull batching) and messages() (stream for push deliver or continuous pull polling in the background).AccountInfo API mapping JetStream tier resource usage and account details.numReplicas and maxAge properties in StreamConfig.publishPayload<T> on the JetStream class.create and update methods supporting optimistic concurrency control (via PubOpts).getRevision to retrieve historical values.KeyValueOp like put, delete, and purge).KeyValue.get().ObjectStoreConfig supporting replicas, maxBytes, and ttl.addLink and addBucketLink methods to align with standard NATS conventions (aliasing/replacing old putLink and putBucketLink).list() to correctly track tombstones and filter deleted object metadata.putBytes and getBytes.Add NATS JetStream Support (Stream/Consumer management, Publish/Subscribe, Pull mode with Ack/Nak/Term)
Nothing published for this version
Issue resolved when app is in background. Thanks nileshsoni97 for contribution.
Fix Uint8List and List inconsistency. Thank myxzlpltk for contribution.
fix Exposing Security Context#31.
fix a bug that does not correctly parse headers containing the ':' character. Thank https://github.com/CoryHagerman for contribution.
* fix nkeys decode issue
* Support verbos acknowledge * Chang pub, pubString to async * Header support (hpub and hmsg)
Add nkeys publicKey privateKey functions
fix #22 error when connect to nats://demo.nats.io
fix #23 Unsupported operation: Platform._version with WebSocket
add generic type to client.request()
fix bug #16 Connect to invalid ws connection does not give error
* fix bug wss: connecting bug
fix bug #20 larger MSG payloads not always working, check if full payload present in buffer
Nothing published for this version
* TLS support
* fix wss://host:port
client.connect() support with url schema example ws://host:port or nats://nost:port
* Update readme
Support TCP socket as 0.2.x by client.tcpConnect()
* Update package dependencies
* Fix flutter web Nuid() error
Change transport from socket to WebSock
Add user passwor authentication
fix request error on second request
* add async support for ping() * add message.respondString
fix defect message delay when sub receive continuous message
Improve receive buffer handling
change some wording from payload to data
* fix defect
add inbox to generate unique inbox subject
Nothing published for this version
add string api client.pubString and message.string
Nothing published for this version
Nothing published for this version
* refactor code * add commend
Nothing published for this version
* publish can be buffered.
* Add readme
* Update readme
* Update sample code
* Update sample code
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →