FolkwaysDocs

Rate limits and flow control

The short-window limits each segment runs under, how the SDK slows down, pauses and retries for you, and what each error means.

Rate limits keep a node predictable and stop one runaway client from slowing everyone else down. They are guardrails, not billing: they count per second (with a short burst allowed) or per minute, never per hour or day. Monthly message and data allowances are a separate thing, set by your plan.

A segment's limits come from its plan: they grow with the package size (concurrent connections) and follow the segment's preset, which shapes them for what the segment is used for. Each node counts on its own, so in a cluster the limits are approximate.

What the SDK does for you

Most apps need no code for any of this:

What happensWhat the SDK doesWhat you see
A publish goes over a rateWaits as long as the node asks, then sends it again with the same idempotency key, until publishTimeoutMsNothing, unless it is still refused after 30 seconds (Timeout)
The segment's deliveries fall behindSends publishes in batches (throttled), or holds them until the node resumes (paused)client.connection.flow
A subscribe or a new topic goes over its per-minute rateTries again after the wait the node asks forsub.ready or the publish settles a little later
Too many new connections at once (the segment's per-minute limit, or too many failed sign-ins from one address)Reconnects after the node's wait, plus some random extra so a crowd of clients doesn't come back togetherThe state stays connecting or reconnecting
A topic already has as many subscribers as the plan allowsNothing: retrying can't helpsub.ready rejects with QuotaExceeded
A payload is over 60 KiBRefuses it before sendingpublish() rejects with PayloadTooLarge

None of these close the connection.

Flow control

When a segment's deliveries go over its outbound byte rate, the node never drops events. It slows the publishers down instead, and the SDK follows:

connection.flowMeansWhat happens to your publishes
'normal'All is wellSent as you make them
'throttled'Deliveries are falling behindStill accepted; the SDK sends them in batches, up to once a second
'paused'Deliveries are more than a second behindHeld in the queue, in order, and sent when the node resumes. Signals are dropped, as when offline

While paused, a publish still waits at most publishTimeoutMs (30 seconds) in total before failing with Timeout, and at most offlineQueue.maxSize publishes (1,000) wait; more fail at once with QueueFull. Nothing is dropped without its promise saying so.

Show it in your UI, for example to grey out a send button:

import { useSyncExternalStore } from 'react';

function SendButton({ client }: { client: Realtime }) {
  const { flow } = useSyncExternalStore(client.connection.subscribe, client.connection.getSnapshot);
  return <button disabled={flow === 'paused'}>{flow === 'throttled' ? 'Send (busy)' : 'Send'}</button>;
}

Or listen for changes:

client.connection.on('flow', ({ state, retryAfterMs }) => {
  console.log(`publishing is ${state}`, retryAfterMs); // how far behind the node's deliveries are
});

See your limits

session.limits shows the limits the node announced for this connection:

const session = await client.connect();
session.limits.publishPerSec; // e.g. 20
session.limits.maxSubscribersPerTopic; // e.g. 5000
LimitScopeOver it
publishPerSec, publishBurstPublishes from this connection, per second, and the burst above itRateLimited
topicPublishPerSec, topicPublishBurstPublishes into one topic from all publishersRateLimited
segmentPublishPerSec, segmentPublishBurstPublishes across the whole segmentRateLimited
inboundBytesPerSecBytes all the segment's clients sendRateLimited on publishes and subscribes
outboundBytesPerSecBytes the segment's subscribers receiveFlow control
maxSubscribersPerTopicSubscribers one topic holds at onceQuotaExceeded on subscribe
subscribesPerMinSubscribes across the segmentRateLimited
topicCreatesPerMinNew topics across the segmentRateLimited
newConnectionsPerMinNew connections across the segmentA connection attempt is turned away, and the SDK retries

A limit is missing when the node doesn't announce it: an older node, or a connection over HTTP long-polling, which has no handshake. The SDK then relies on the node's answers alone, as it always does.

Limits by preset

Each preset gives the limits a different shape. The numbers depend on your plan and package size, and may change, so read them from session.limits rather than hard-coding them.

PresetBuilt forShape
GeneralSegments that chose no presetBalanced
AI streamingToken streams from a modelA high publish rate into a few topics, high inbound bytes, fewer subscribers per topic
ChatRooms and conversationsMany topics, each with a low publish rate; more topic creations and subscribes per minute
Live dashboardMany viewers of the same dataVery many subscribers per topic and high outbound bytes
IoTMany small devicesA low rate per connection, a high rate across the segment

Segment-wide limits grow with the package, never below a floor that keeps small packages working. The payload cap is the same on every package: 60 KiB per event (limits.maxPayloadBytes, 61,440 bytes).

What each error means

ErrorMeansWhat to do
RateLimited (300)Over one of the rates above, or publishing is paused. Nothing was doneThe SDK retries after retryAfterMs. If publishes still time out, publish less often
QuotaExceeded (301)A count is full: subscribers on this topic, topics in the segment, connections, or the month's messagesRetrying soon won't help. Unsubscribe elsewhere, raise the limit in Settings, or upgrade the plan
PayloadTooLarge (302)The payload is over 60 KiBSend less, or a reference to the data
Backpressure (303)This connection read too slowly and was closedNothing: the SDK reconnects and resumes without losing events

Staying under the limits

  • Batch high-frequency updates. A cursor or a progress bar doesn't need every intermediate value: send the latest every 100 ms or so.
  • Use the right delivery type. Latest-value state belongs in kv, and "who is typing" in signals, which are cheap and dropped when stale.
  • Stream AI output in sensible chunks. One event per few tokens is plenty; 60 KiB holds about 10,000 tokens.
  • Reuse topics. Creating topics on every page view counts against topicCreatesPerMin.
  • Don't reconnect on your own. The SDK already spreads reconnects out. Opening new clients in a loop is what the connection limits are there to stop.

On this page