# Storage & Queues (/docs/configure/reference/storage-queues)



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 [#persistent-store]

Limits and retention for the persistent store. The **persistence engine** is chosen once
at cluster creation — see [Storage Engines](/docs/configure/reference/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. All ten store fields are fully CRD-settable under
`spec.store.*`.

| Setting                  | Type   | Default   | Valid values         | Docker (config.yaml key · env var)                             | Helm/CRD path                         | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ------------------------ | ------ | --------- | -------------------- | -------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Persistence engine       | string | `legacy`  | `legacy` \| `next`   | `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. Empty normalizes to `legacy` on non-Kafka paths. When the Kafka connector is enabled and the engine is unset, it is auto-selected — see [Storage Engines](/docs/configure/reference/storage-engines#zero-config-engine-selection).                                                                                                                                                                                                                                   |
| Clean store on start     | bool   | `false`   | true / false         | `store.cleanstore` · `STORE_CLEAN_STORE`                       | `spec.store.clean`                    | 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. &#x2A;*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](/docs/configure/reference/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`. &#x2A;*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`).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

<Callout type="warn">
  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.
</Callout>

<Callout type="warn">
  **These limits are enforced by the `legacy` engine only.** 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 on `next` 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](/docs/configure/reference/storage-engines#native-retention-scope).
</Callout>

## Queues [#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.                                                                |

<Callout type="warn">
  **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&#x2A; would fail server validation. Treat the
  effective minimum for every queue setting as &#x2A;*`1`**.
</Callout>

## Example [#example]

Set message retention on each target. This is a single-setting snippet — see the
[Docker guide](/docs/configure/docker) and the
[Kubernetes guide](/docs/configure/kubernetes) for complete, runnable configurations.

<Tabs items="[&#x22;Docker&#x22;, &#x22;Helm&#x22;]">
  <Tab value="Docker">
    ```yaml title="config.yaml"
    store:
      maxretention: 1440
    ```
  </Tab>

  <Tab value="Helm">
    ```yaml title="values.yaml"
    store:
      messagesRetentionMinutes: 1440
    ```
  </Tab>
</Tabs>

For the full Docker delivery methods (env vars, mounted `config.yaml`, the `CONFIG`
variable) see the [Docker guide](/docs/configure/docker); for `values.yaml` mapped to
the `KubemqCluster` spec see the [Kubernetes guide](/docs/configure/kubernetes).
