An unlimited JetStream account is a non-system NATS account that has JetStream enabled but no memory or disk storage limits configured. Without limits, a single account can consume the entire server’s JetStream reservation, starving every other account of storage resources.
JetStream accounts without storage limits violate the most basic principle of multi-tenant resource management: isolation. When any account can allocate unlimited streams with unlimited storage, there is no mechanism preventing one team’s backfill job, misconfigured retention policy, or runaway producer from consuming every byte of disk or memory the server has reserved for JetStream. The failure mode isn’t theoretical — it’s a matter of when, not if.
The blast radius extends beyond the offending account. When one account exhausts the server’s JetStream file storage, every other account’s stream creation fails. Existing streams across all accounts start rejecting publishes once storage is full. In clustered deployments, the exhaustion propagates to every server that hosts replicas of the unlimited account’s streams. A single account’s unbounded growth can trigger the Storage Utilization Critical check (JETSTREAM_007) cluster-wide, turning an optimization issue into a critical outage.
Even in single-tenant deployments, unlimited accounts create operational blind spots. Without explicit limits, there is no early warning when consumption approaches capacity. The JetStream Resource Pressure check (SERVER_005) fires at 90% of the server reservation, but if the account limit is “everything the server has,” that warning comes too late to avoid impact. Setting explicit account limits creates a buffer between what an account is allowed to use and what the server can provide — the difference between a graceful rejection and a cluster-wide storage crisis.
Default account configuration. New accounts created without explicitly setting JetStream limits default to unlimited. This is common in development environments that get promoted to production without a configuration review.
Single-tenant assumption. Operators running a single application on NATS often skip account limits because “there’s only one tenant.” But applications grow, teams add workloads, and the single-tenant assumption breaks silently when a second team starts creating streams.
Migration from core NATS. Teams migrating from core NATS (publish/subscribe only) to JetStream may enable JetStream on existing accounts without adding storage limits. The account was fine without limits when it had no persistent state — now it has unbounded storage authority.
Operator JWT without JetStream claims. When using the NATS JWT-based auth system, the account JWT must include explicit JetStream limits. If the operator issues an account JWT with JetStream enabled but omits the mem_storage and disk_storage claims, the account gets unlimited access.
Copy-paste from examples. Many NATS configuration examples and tutorials use -1 (unlimited) for JetStream limits to simplify the getting-started experience. Production deployments that copy these values inherit the risk.
Use the nats CLI to inspect account information:
nats account infoLook for the JetStream section. If Memory and Storage limits show -1 or unlimited, the account has no resource cap.
To find all unlimited accounts, query the server’s account information endpoint:
curl -s http://localhost:8222/accountz | jq '.accounts[] | select(.jetstream == true) | {name: .account_name, mem_limit: .memory, store_limit: .storage}'Any account with mem_limit or store_limit of -1 is unlimited.
For deployments using the NATS JWT auth system, inspect account claims:
nsc describe account <account_name>Look for the JetStream section — Max Mem Storage and Max Disk Storage of -1 confirm the account is unlimited.
Even if an unlimited account isn’t causing problems today, check how much headroom remains:
nats server report jetstreamCompare each server’s used storage against its total JetStream reservation. An unlimited account currently using 80% of available storage is one traffic spike away from exhaustion.
Determine what the unlimited account is actually using. Before setting limits, understand current consumption so you don’t set limits below current usage (which would prevent new stream creation):
nats account info --json | jq '{mem_used: .memory, store_used: .storage, streams: .streams, consumers: .consumers}'Calculate appropriate limits. A good starting point: set the account limit to 150% of current usage, or divide the total server reservation proportionally across accounts. Leave at least 20% of the server’s total JetStream reservation unallocated as headroom.
For static configuration (accounts block):
1accounts {2 ORDERS {3 jetstream {4 max_mem: 512M5 max_file: 50G6 max_streams: 257 max_consumers: 1008 }9 users = [{user: "order-svc", password: "$ORDERS_PASS"}]10 }11}For JWT-based deployments using NSC:
nsc edit account ORDERS \ --js-mem-storage 512M \ --js-disk-storage 50G \ --js-streams 25 \ --js-consumer 100Push the updated account JWT:
nsc push -a ORDERSProgrammatic account limit configuration in Go:
1// Go — creating a stream that respects account limits2js, _ := nc.JetStream()3
4// The server enforces account limits automatically.5// This create will fail if it would exceed the account's max_file or max_streams.6_, err := js.AddStream(&nats.StreamConfig{7 Name: "ORDERS",8 Subjects: []string{"ORDERS.>"},9 MaxBytes: 10 * 1024 * 1024 * 1024, // 10GB per-stream limit10 Replicas: 3,11})12if err != nil {13 // nats.ErrJetStreamResourcesExceeded if account limit hit14 log.Fatalf("stream create failed: %v", err)15}1# Python — handling account limit errors2import nats3from nats.js.errors import BadRequestError4
5nc = await nats.connect()6js = nc.jetstream()7
8try:9 await js.add_stream(name="ORDERS", subjects=["ORDERS.>"],10 max_bytes=10 * 1024**3)11except BadRequestError as e:12 # Server rejects if account storage limit exceeded13 print(f"Account limit hit: {e}")Establish account provisioning standards. Every new account should have JetStream limits set at creation time. Document the expected limits for each workload class (e.g., “microservice accounts get 1GB mem / 50GB disk / 10 streams / 50 consumers”).
Set stream-level limits within accounts. Account limits cap total usage, but individual streams within the account should also have retention limits (max_bytes, max_msgs, max_age). This is flagged separately by the Streams Without Limits check (OPT_SYS_001). Defense in depth: account limits prevent cross-tenant impact, stream limits prevent intra-account waste.
Monitor account utilization. Set up alerts when account usage approaches limits so you can proactively adjust before applications start getting rejected.
Synadia Insights evaluates this automatically across all accounts, flagging unlimited accounts as optimization opportunities and near-limit accounts as operational warnings (ACCOUNTS_001).
Yes, as long as you set the limits above the account’s current usage. If you set a storage limit below what the account is already consuming, existing streams continue to function, but the account cannot create new streams or expand existing ones until usage drops below the limit. Check current usage with nats account info before setting limits.
The server rejects new stream creation and publish operations that would exceed the limit. Existing streams continue to serve reads and consumer operations. Streams with retention policies (max_age, max_bytes) will continue to expire old messages, which frees storage and allows new publishes to resume. The account receives a specific error code indicating resource exhaustion.
No. The NATS system account ($SYS) is excluded from this check intentionally. The system account is used for internal server coordination and monitoring — its JetStream usage is controlled by the server itself, not by external workloads. Setting limits on the system account can interfere with server operations.
Start by assigning each account limits based on its expected workload, not by dividing total capacity equally. A stream processing pipeline that ingests 1TB/day needs more storage than an account running lightweight request-reply. Over-provision slightly (sum of all account limits can exceed server capacity by 20-30%) since not all accounts peak simultaneously — but monitor utilization to validate this assumption.
Server JetStream reservation (max_file_store, max_mem_store in the server config) sets the total capacity the server makes available for JetStream. Account limits divide that capacity among accounts. Think of the server reservation as the total pie and account limits as slices. Without account limits, any account can eat the entire pie.
With 100+ always-on audit Checks from the NATS experts, Insights helps you find and fix problems before they become costly incidents.
No alert rules to write. No dashboards to maintain.
News and content from across the community