Default Configs
The transport ships with production-ready defaults for every stream and consumer type. This page lists the exact values from the source code. All defaults can be overridden via module configuration.
Stream Defaults
All streams share a common base configuration:
| Property | Value |
|---|---|
retention | Workqueue (overridden per type below) |
storage | File |
num_replicas | 1 (see production recommendation below) |
discard | Old |
allow_direct | true |
compression | S2 |
All streams default to S2 compression, a Snappy-compatible codec with better ratios. This reduces disk I/O and storage with modest CPU overhead that varies with payload entropy and size. Requires NATS Server >= 2.10 (see runtime requirements). Override per stream kind:
import { StoreCompression } from '@nats-io/jetstream';
events: {
stream: { compression: StoreCompression.None }, // disable for event streams
}
Event Stream
Workqueue retention — each message is removed after being acknowledged by a consumer.
| Property | Value | Notes |
|---|---|---|
retention | Workqueue | |
storage | File | |
num_replicas | 1 | |
allow_rollup_hdrs | true | |
max_consumers | 100 | |
max_msg_size | 10 MB | 10,485,760 bytes |
max_msgs_per_subject | 5,000,000 | |
max_msgs | 50,000,000 | |
max_bytes | 5 GB | 5,368,709,120 bytes |
max_age | 7 days | toNanos(7, 'days') |
duplicate_window | 2 minutes | toNanos(2, 'minutes') |
To enable message scheduling, add allow_msg_schedules: true to the event stream config. This requires NATS Server >= 2.12.
Command Stream
Short-lived RPC commands (JetStream RPC mode only).
| Property | Value | Notes |
|---|---|---|
retention | Workqueue | |
storage | File | |
num_replicas | 1 | |
allow_rollup_hdrs | false | |
max_consumers | 50 | |
max_msg_size | 5 MB | 5,242,880 bytes |
max_msgs_per_subject | 100,000 | |
max_msgs | 1,000,000 | |
max_bytes | 100 MB | 104,857,600 bytes |
max_age | 3 minutes | toNanos(3, 'minutes') |
duplicate_window | 30 seconds | toNanos(30, 'seconds') |
Broadcast Stream
Limits retention — messages persist until the configured limits are reached. Shared across all services.
| Property | Value | Notes |
|---|---|---|
retention | Limits | |
storage | File | |
num_replicas | 1 | |
allow_rollup_hdrs | true | |
max_consumers | 200 | |
max_msg_size | 10 MB | 10,485,760 bytes |
max_msgs_per_subject | 1,000,000 | |
max_msgs | 10,000,000 | |
max_bytes | 2 GB | 2,147,483,648 bytes |
max_age | 1 hour | toNanos(1, 'hours') |
duplicate_window | 2 minutes | toNanos(2, 'minutes') |
max_age reduced from 1 day to 1 hour. Broadcast messages (config propagation, cache invalidation, feature flags) are relevant for minutes, not days. 1 hour provides sufficient catch-up window for new instances while reducing unnecessary storage. This is a mutable property — existing streams update automatically on next startup.
Ordered Stream
Limits retention for strict sequential delivery. Ordered consumers are ephemeral.
| Property | Value | Notes |
|---|---|---|
retention | Limits | |
storage | File | |
num_replicas | 1 | |
allow_rollup_hdrs | false | |
max_consumers | 100 | |
max_msg_size | 10 MB | 10,485,760 bytes |
max_msgs_per_subject | 5,000,000 | |
max_msgs | 50,000,000 | |
max_bytes | 5 GB | 5,368,709,120 bytes |
max_age | 1 day | toNanos(1, 'days') |
duplicate_window | 2 minutes | toNanos(2, 'minutes') |
DLQ Stream
Workqueue retention — dead letters are removed when a DLQ consumer acks them. Created on demand when dlq: { stream } is set in forRoot(). See Dead Letter Queue — Built-in DLQ stream.
| Property | Value | Notes |
|---|---|---|
retention | Workqueue | |
storage | File | |
num_replicas | 1 | |
allow_rollup_hdrs | false | |
max_consumers | 100 | |
max_msg_size | 10 MB | 10,485,760 bytes |
max_msgs_per_subject | 5,000,000 | |
max_msgs | 50,000,000 | |
max_bytes | 5 GB | 5,368,709,120 bytes |
max_age | 30 days | toNanos(30, 'days') |
duplicate_window | 2 minutes | toNanos(2, 'minutes') |
Consumer Defaults
Event Consumer
| Property | Value | Notes |
|---|---|---|
ack_wait | 10 seconds | toNanos(10, 'seconds') |
max_deliver | 3 | Message moves to dead-letter after 3 failed attempts |
max_ack_pending | 100 | |
ack_policy | Explicit | |
deliver_policy | All | |
replay_policy | Instant |
Command Consumer
| Property | Value | Notes |
|---|---|---|
ack_wait | 5 minutes | toNanos(5, 'minutes') |
max_deliver | 1 | No retries — RPC failures propagate immediately |
max_ack_pending | 100 | |
ack_policy | Explicit | |
deliver_policy | All | |
replay_policy | Instant |
Broadcast Consumer
| Property | Value | Notes |
|---|---|---|
ack_wait | 10 seconds | toNanos(10, 'seconds') |
max_deliver | 3 | |
max_ack_pending | 100 | |
ack_policy | Explicit | |
deliver_policy | All | |
replay_policy | Instant |
Ordered consumers do not have a durable consumer configuration. They are ephemeral and managed entirely by the @nats-io/jetstream client library.
Connection Defaults
The transport applies the following connection defaults for production resilience:
| Property | Value | Notes |
|---|---|---|
maxReconnectAttempts | -1 | Unlimited reconnection attempts |
reconnectTimeWait | 1000 | 1 second between reconnection attempts |
These defaults ensure the transport automatically recovers from transient network failures without manual intervention. Override them via connectionOptions in forRoot():
JetstreamModule.forRoot({
name: 'orders',
servers: ['nats://localhost:4222'],
connectionOptions: {
maxReconnectAttempts: 10, // limit to 10 attempts
reconnectTimeWait: 2_000, // 2 seconds between attempts
},
})
RPC Timeouts
| Mode | Default Timeout | Constant |
|---|---|---|
| Core (standard NATS request-reply) | 30 seconds | DEFAULT_RPC_TIMEOUT |
| JetStream (persistent RPC) | 3 minutes | DEFAULT_JETSTREAM_RPC_TIMEOUT |
The JetStream RPC timeout is intentionally longer because messages are persisted to a stream and the consumer may take time to process them.
Graceful Shutdown Timeout
| Property | Value |
|---|---|
| Shutdown timeout | 10 seconds |
On shutdown, the transport calls drain() on the NATS connection and waits up to 10 seconds for it to complete before forcing the connection closed. Increase this timeout if your handlers have long-running I/O that must finish cleanly.
Replicas in production
The default num_replicas: 1 is suitable for development and single-node NATS. For production NATS clusters, set num_replicas: 3 to ensure data survives node failures via Raft consensus:
JetstreamModule.forRoot({
name: 'orders',
servers: ['nats://nats-1:4222', 'nats://nats-2:4222', 'nats://nats-3:4222'],
events: { stream: { num_replicas: 3 } },
broadcast: { stream: { num_replicas: 3 } },
ordered: { stream: { num_replicas: 3 } },
rpc: { mode: 'jetstream', stream: { num_replicas: 3 } },
});
num_replicas can be changed on an existing stream — NATS will add or remove replicas automatically. No downtime or stream recreation required.
Immutable vs mutable stream properties
NATS JetStream divides stream configuration into properties that can be updated on an existing stream and properties that are locked at creation time.
Mutable (can be changed at any time)
num_replicas, max_age, max_bytes, max_msgs, max_msg_size, max_msgs_per_subject, discard, duplicate_window, subjects, compression, description, allow_rollup_hdrs, allow_direct
The transport applies mutable changes automatically on startup — just update the value in forRoot() and restart the service.
Enable-only (can be turned on, but never off)
These properties can be enabled on an existing stream via a normal update, but once enabled they cannot be disabled. No stream recreation required.
| Property | Default | Notes |
|---|---|---|
allow_msg_schedules | false | Enable message scheduling — safe to add to existing streams |
allow_msg_ttl | false | Enable per-message TTL |
deny_delete | false | Prevent message deletion via API |
deny_purge | false | Prevent stream purging via API |
You can safely add allow_msg_schedules: true to an existing stream config — NATS applies this as a regular update. No downtime, no message loss, no stream recreation. Just update forRoot() and restart.
Immutable (locked after creation)
| Property | Default | Migratable | Notes |
|---|---|---|---|
name | derived from service name | No | Cannot be renamed |
retention | Workqueue or Limits | No | Controlled by the transport — a mismatch is always an error |
storage | File | Yes | Can be migrated with allowDestructiveMigration: true |
The transport can automatically migrate storage via blue-green stream recreation. See the full Stream Migration guide for how it works, rolling update behavior, performance benchmarks, and limitations.
retention is controlled by the transport (Workqueue for events/commands, Limits for broadcast/ordered). A mismatch between the running stream and the expected retention policy always throws an error on startup, regardless of allowDestructiveMigration.
Overriding Defaults
All stream and consumer defaults can be overridden in forRoot() options. User-provided values are merged on top of the defaults — you only need to specify the properties you want to change.
import { RetentionPolicy, StorageType } from '@nats-io/jetstream';
import { JetstreamModule, toNanos } from '@horizon-republic/nestjs-jetstream';
JetstreamModule.forRoot({
name: 'orders',
servers: ['nats://localhost:4222'],
events: {
stream: {
storage: StorageType.Memory, // override just storage type
max_age: toNanos(3, 'days'), // 3 days instead of 7
},
consumer: {
max_deliver: 5, // 5 retries instead of 3
},
},
rpc: {
mode: 'jetstream',
timeout: 60_000, // 1 minute instead of 3
stream: {
max_msg_size: 1024 * 1024, // 1 MB limit for RPC payloads
},
},
});
See Module Configuration for the full options reference.
Exported constants
Every default above is exposed as a typed constant from the package, so you can import and reuse it when composing overrides programmatically or writing tests.
Stream and consumer defaults:
| Constant | Contents |
|---|---|
DEFAULT_EVENT_STREAM_CONFIG | Event (workqueue) stream defaults |
DEFAULT_BROADCAST_STREAM_CONFIG | Broadcast stream defaults (shared broadcast-stream) |
DEFAULT_ORDERED_STREAM_CONFIG | Ordered stream defaults |
DEFAULT_COMMAND_STREAM_CONFIG | JetStream RPC command stream defaults |
DEFAULT_DLQ_STREAM_CONFIG | Dead Letter Queue stream defaults |
DEFAULT_EVENT_CONSUMER_CONFIG | Event consumer defaults |
DEFAULT_BROADCAST_CONSUMER_CONFIG | Broadcast consumer defaults |
DEFAULT_COMMAND_CONSUMER_CONFIG | JetStream RPC command consumer defaults |
Timeouts:
| Constant | Value |
|---|---|
DEFAULT_RPC_TIMEOUT | 30_000 (Core mode timeout, ms) |
DEFAULT_JETSTREAM_RPC_TIMEOUT | 180_000 (JetStream mode timeout, ms) |
DEFAULT_SHUTDOWN_TIMEOUT | 10_000 (graceful shutdown drain timeout, ms) |
Handler metadata registry:
| Constant | Value |
|---|---|
DEFAULT_METADATA_BUCKET | 'handler_registry' |
DEFAULT_METADATA_REPLICAS | 1 |
DEFAULT_METADATA_HISTORY | 1 |
DEFAULT_METADATA_TTL | 30_000 (heartbeat-refreshed entry TTL, ms) |
MIN_METADATA_TTL | 5_000 (minimum configurable TTL, ms) |
Other:
RESERVED_HEADERS— theSet<string>of header names blocked byJetstreamRecordBuilder.setHeader(). See Record Builder.
import { DEFAULT_EVENT_STREAM_CONFIG, toNanos } from '@horizon-republic/nestjs-jetstream';
events: {
stream: { ...DEFAULT_EVENT_STREAM_CONFIG, max_age: toNanos(14, 'days') },
}