Storage & Queues
Persistent store limits and retention, plus queue delivery defaults and ceilings.
KubeMQ persists messages through an embedded persistent store and serves pull-based
delivery through its queues. The store controls how much is retained and for how long;
the queue settings control visibility, wait, delay, expiration, and retry behavior. Each
setting is shown for both deployment targets — Docker single-node (config.yaml key · env
var) and Kubernetes/Helm (spec.* path). A dash (—) in the Helm/CRD column means the
setting is not available on that surface.
Store and queue tuning is opt-out: the store and queue blocks are internal
server sections (not wire connectors), so they are always active with the defaults below —
there is no enable/disabled toggle. Override only the fields you need.
Persistent store
Limits and retention for the persistent store. The persistence engine is chosen once
at cluster creation — see Storage Engines for
the full engine model, durability guarantees, and clustering. Several store fields carry
name divergences between the Docker config.yaml key and the Helm/CRD field — the
Notes column flags each one. The ten fields below are all CRD-settable under
spec.store.*; the store config carries five more — the next-engine settings
(nextackpolicy, nextraftaddress, nextsegmentsize, nextshards,
nextbalanceleaders), which are config.yaml/env-only and documented on
Storage Engines.
| Setting | Type | Default | Valid values | Docker (config.yaml key · env var) | Helm/CRD path | Notes |
|---|---|---|---|---|---|---|
| Persistence engine | string | unset → resolved from the store directory (clean ⇒ next) | legacy | next | auto | store.engine · STORE_ENGINE | spec.store.engine (typed CRD enum) | Chosen once, at cluster creation — a cluster is born one mode and stays there; no in-place migration. Unset (or the explicit auto) does not mean legacy: the server probes the store directory and resolves the engine that wrote it, or next for a clean one. To get legacy you must name it. See Zero-config engine selection. |
| Clean store on start | bool | false | true / false | store.cleanstore · STORE_CLEAN_STORE | spec.store.clean | ⚠️ Destructive — wipes the store on every boot. See the warning below. Name divergence: cleanstore ↔ clean. CRD emits STORE_CLEAN_STORE=true only when clean: true; otherwise unset. |
| Store path | string | ./store | non-empty file path | store.storepath · STORE_STORE_PATH | spec.store.path | Name divergence: storepath ↔ path. Empty string is rejected. On the legacy engine, absolute paths are rewritten to relative: a leading / is prefixed with . (so /data becomes ./data). On the next engine, an absolute StorePath is honored verbatim (e.g. a mounted PVC path like /store) — no rewrite. This is server-process behavior; on Kubernetes the operator supplies the mount and rejects a leading / in spec.store.path outright (see Deployment) — the two layers aren't in conflict. |
| Max channels | int | 0 (∞) | ≥ 0; 0 = unlimited | store.maxqueues · STORE_MAX_QUEUES | spec.store.maxChannels | Name divergence: store.maxqueues ↔ spec.store.maxChannels. Negative rejected. 0 logs a stderr WARNING (unbounded). |
| Max channel size (bytes) | int64 | 0 (∞) | ≥ 0; 0 = unlimited | store.maxqueuesize · STORE_MAX_QUEUE_SIZE | spec.store.maxChannelSize | Name divergence: store.maxqueuesize ↔ spec.store.maxChannelSize. Type divergence: server field is int64; the CRD field is *int32, so via Helm the max is ~2.1 GB — set larger caps through config.yaml/env. 0 logs a stderr WARNING. |
| Max messages / channel | int | 0 (∞) | ≥ 0; 0 = unlimited | store.maxmessages · STORE_MAX_MESSAGES | spec.store.maxMessages | Negative rejected. 0 logs a stderr WARNING. |
| Max subscribers | int | 0 (∞) | ≥ 0; 0 = unlimited | store.maxsubscribers · STORE_MAX_SUBSCRIBERS | spec.store.maxSubscribers | Negative rejected. 0 logs a stderr WARNING. |
| Message retention (min) | int | 1440 | ≥ 0 (minutes) | store.maxretention · STORE_MAX_RETENTION | spec.store.messagesRetentionMinutes | Name divergence: store.maxretention ↔ spec.store.messagesRetentionMinutes. Negative rejected. |
| Purge inactive (min) | int | 1440 | ≥ 0 (minutes) | store.maxpurgeinactive · STORE_MAX_PURGE_INACTIVE | spec.store.purgeInactiveMinutes | Name divergence: store.maxpurgeinactive ↔ spec.store.purgeInactiveMinutes. Negative rejected. |
| Idle prune cutoff (hrs) | int | 24 | ≥ 1 | store.idleprunecutoffhours · STORE_IDLE_PRUNE_CUTOFF_HOURS | spec.store.idlePruneCutoffHours | Must be at least 1 (server rejects 0; CRD schema enforces minimum: 1). |
store.cleanstore: true deletes the persistent store on every single boot — not once.
It is not a one-shot reset. Left in a values.yaml or a config.yaml, every pod roll,
node drain, crash-restart, and routine upgrade wipes production data — and every restart
looks completely healthy, because deleting the store is exactly what you asked for.
Use it for a deliberate, supervised reset and take it back out immediately. There is no confirmation, no dry-run, and no undo.
Two things bound the damage, neither of which is a safety net you should rely on: the
engine-mode guard runs before the wipe, so a mode-mismatched or unrecognized directory
fails fast and is never deleted; and on a clustered next cluster the server refuses
to wipe a member's datadir outright, telling you to remove the member from the cluster
first. A standalone node has neither protection.
Leaving any of Max channels / Max channel size / Max messages / Max subscribers at
its default of 0 means unlimited and prints a startup WARNING to stderr — the store
places no bound on that dimension, which can drive unbounded memory/disk use in
production. Set explicit ceilings for production workloads.
These limits are enforced by the legacy engine only — and next is what a new
cluster gets. A fresh install on a clean store resolves to next, so the default
deployment enforces no retention at all, including the 1440-minute Message retention
and Purge inactive values printed in the table above. Those two rows describe legacy.
On the next engine, Max channels / Max channel size / Max messages / Message retention
/ Purge inactive are not consumed — a native Events Store or Queues channel has no age, size, or
count cap and grows unbounded under a slow or absent consumer. Size next deployments by
disk capacity, or use Kafka topic channels (whose retention.ms is age-enforced on
next) where eviction matters. See
Storage Engines.
Queues
Delivery defaults and ceilings for pull-based queues. Two Docker keys diverge from the
Helm/CRD field names — queue.maxreceivecount ↔ spec.queue.maxReQueues (the retry
ceiling) and queue.maxnumberofmessages ↔ spec.queue.maxReceiveMessagesRequest (the
per-request batch). All ten queue fields are fully CRD-settable under spec.queue.*.
| Setting | Type | Default | Valid values | Docker (config.yaml key · env var) | Helm/CRD path | Notes |
|---|---|---|---|---|---|---|
| Default visibility (s) | int32 | 60 | > 0 | queue.defaultvisibilityseconds · QUEUE_DEFAULT_VISIBILITY_SECONDS | spec.queue.defaultVisibilitySeconds | |
| Default wait timeout (s) | int32 | 1 | > 0 | queue.defaultwaittimeoutseconds · QUEUE_DEFAULT_WAIT_TIMEOUT_SECONDS | spec.queue.defaultWaitTimeoutSeconds | |
| Max visibility (s) | int32 | 43200 | > 0 | queue.maxvisibilityseconds · QUEUE_MAX_VISIBILITY_SECONDS | spec.queue.maxVisibilitySeconds | 43200 s = 12 h. |
| Max wait timeout (s) | int32 | 3600 | > 0 | queue.maxwaittimeoutseconds · QUEUE_MAX_WAIT_TIMEOUT_SECONDS | spec.queue.maxWaitTimeoutSeconds | |
| Max delay (s) | int32 | 43200 | > 0 | queue.maxdelayseconds · QUEUE_MAX_DELAY_SECONDS | spec.queue.maxDelaySeconds | 43200 s = 12 h. |
| Max expiration (s) | int32 | 43200 | > 0 | queue.maxexpirationseconds · QUEUE_MAX_EXPIRATION_SECONDS | spec.queue.maxExpirationSeconds | 43200 s = 12 h. |
| Retry ceiling (→ DLQ) | int32 | 1024 | > 0 | queue.maxreceivecount · QUEUE_MAX_RECEIVE_COUNT | spec.queue.maxReQueues | Name divergence: queue.maxreceivecount ↔ spec.queue.maxReQueues. Max redeliveries before dead-lettering. |
| Max messages / receive req | int32 | 1024 | > 0 | queue.maxnumberofmessages · QUEUE_MAX_NUMBER_OF_MESSAGES | spec.queue.maxReceiveMessagesRequest | Name divergence: queue.maxnumberofmessages ↔ spec.queue.maxReceiveMessagesRequest. Per-request batch ceiling. |
| Max inflight | int32 | 2048 | > 0 | queue.maxinflight · QUEUE_MAX_INFLIGHT | spec.queue.maxInflight | Max unacked in-flight messages per queue. |
| Pub-ack wait (s) | int32 | 60 | > 0 | queue.pubackwaitseconds · QUEUE_PUB_ACK_WAIT_SECONDS | spec.queue.pubAckWaitSeconds | Publish-ack wait before the send is considered failed. |
Every queue field must be greater than 0 — the server rejects 0 at startup. The
CRD schema already enforces this with minimum: 1 on all ten queue fields, so a Helm
value of 0 is rejected by the API server and would fail server validation. Treat the
effective minimum for every queue setting as 1.
Example
Set message retention on each target. This is a single-setting snippet — see the Docker guide and the Kubernetes guide for complete, runnable configurations.
store:
maxretention: 1440store:
messagesRetentionMinutes: 1440For the full Docker delivery methods (env vars, mounted config.yaml, the CONFIG
variable) see the Docker guide; for values.yaml mapped to
the KubemqCluster spec see the Kubernetes guide.
Was this page helpful?
Connectors
Runtime settings for MCP, A2A agents, CloudEvents, and the wire-protocol connectors — MQTT, AMQP 0.9.1/1.0, STOMP, Kafka, AWS, and GCP Pub/Sub.
Storage Engines
The two persistence engines — next and legacy — how the engine is chosen, mode isolation, durability, compaction, and next-engine clustering.