Deploy
Configuration
Nexir loads configuration at startup. Change TOML or environment variables, then restart the node; runtime CONFIG SET is not supported.
Loading and precedence
- Load a local
.envfile if present. - Load
config/default.tomlif present relative to the working directory. - Apply
NEXIR__*environment variables.
Environment variables override TOML. Existing shell variables override values from .env. Nested names use double underscores:
NEXIR__SERVER__REDIS_BIND=127.0.0.1:16379
NEXIR__SERVER__TLS__CLIENT__MODE=require
NEXIR__STORAGE__PATH=/var/lib/nexirEssential settings
| TOML field | Environment variable | Default |
|---|---|---|
server.redis_bind | NEXIR__SERVER__REDIS_BIND | 127.0.0.1:6379 |
server.grpc_bind | NEXIR__SERVER__GRPC_BIND | 127.0.0.1:50051 |
server.default_read_mode | NEXIR__SERVER__DEFAULT_READ_MODE | LINEARIZABLE |
server.enable_admin_commands | NEXIR__SERVER__ENABLE_ADMIN_COMMANDS | false |
raft.node_id | NEXIR__RAFT__NODE_ID | 1 |
storage.path | NEXIR__STORAGE__PATH | ./data/nexir |
prometheus.bind | NEXIR__PROMETHEUS__BIND | 127.0.0.1:9090 |
TLS settings
Both TLS surfaces default to disabled. require means mutual TLS and requires a certificate, matching private key, and CA bundle.
| Surface | Fields under server.tls | Environment prefix |
|---|---|---|
| RESP clients | client.mode, cert_file, key_file, ca_bundle | NEXIR__SERVER__TLS__CLIENT__* |
| Raft peers | cluster.mode, cert_file, key_file, ca_bundle | NEXIR__SERVER__TLS__CLUSTER__* |
Use separate client and cluster CA bundles. Startup rejects the same resolved CA file for both required surfaces. TLS files are read at startup; rotation requires restart.
Server resource defaults
| Field | Default | Purpose |
|---|---|---|
max_connections | 10,000 | Concurrent RESP clients |
max_inflight_commands_global | 100,000 | Unfinished commands across clients |
max_inflight_commands_per_connection | 1,000 | Per-client command budget |
max_inflight_bytes_global | 512 MiB | Global in-flight request payload budget |
max_inflight_bytes_per_connection | 64 MiB | Per-client payload budget |
max_client_buffer_bytes | 64 MiB | Unread input per socket |
max_buffered_client_bytes_global | 512 MiB | Buffered input across clients |
client_idle_timeout_secs | 300 | Idle RESP socket timeout |
max_concurrent_reads_per_connection | 16 | Concurrent reads for one client |
max_buffered_response_bytes_per_connection | 64 MiB | Queued output per client |
max_buffered_response_bytes_global | 512 MiB | Queued output globally |
Storage defaults
| Field | Default | Notes |
|---|---|---|
block_cache_size_mb | 0 (derived) | The node's one shared block cache: 50% of the process target |
write_buffer_size_mb | 128 | State DB buffer; log DB uses twice this |
max_write_buffers | 4 | Storage-engine write buffers |
enable_bloom_filters | true | Point lookup filters |
read_io_threads | 0 (auto) | Available cores clamped to 4–64 |
write_io_threads | 2 | Blocking write workers |
cleanup_io_threads | 1 | Background cleanup worker |
max_read_reply_bytes | 0 → 64 MiB | Resolves to per-client response limit |
max_reader_pin_ms | 300,000 | Five-minute maximum read lifetime |
max_snapshot_files | 10,000 | Accepted snapshot file count |
max_snapshot_size_bytes | 64 GiB | Snapshot size cap; must match across nodes |
max_archive_bytes | 64 GiB | Snapshot transfer cap; must match across nodes |
max_retained_snapshot_bytes | 256 GiB | Retained snapshot budget |
min_free_disk_bytes | 1 GiB | Free-space reserve: snapshot receives are refused and snapshot builds deferred below it |
Memory defaults
Each node plans its memory once at startup from the smaller of its host memory and any container (cgroup) limit. These are targets and capacities, not hard ceilings on resident memory. Every field is under [memory]; 0 means derived.
| Field | Default | Notes |
|---|---|---|
process_target_bytes | 0 (derived) | Process target P: 75% of available memory. New writes are refused with -TRYAGAIN while resident memory is at 90% of it |
state_memtable_bytes / log_memtable_bytes | 0 (derived) | Write-buffer capacity for the state database and the Raft log |
reserved_headroom_bytes | 0 (derived) | What remains of P; client replies must fit in half of it |
With default settings a host of about 6 GB or more starts; a 4 GiB node is refused at startup until connection, in-flight command or response limits are lowered. See the configuration reference.
Raft defaults
| Field | Default |
|---|---|
snapshot_policy_logs | 100,000 |
max_pending_write_tasks | 10,000 |
max_pending_write_bytes | 256 MiB |
max_inflight_read_barriers | 10 |
max_queued_linearizable_reads | 100,000 |
membership_preflight_timeout_ms | 3,000 |
membership_change_timeout_ms | 30,000 |
add_learner_catchup_timeout_ms | 300,000 |
transfer_leader_timeout_ms | 10,000 |
heartbeat_interval_ms | 1,000 |
election_timeout_min_ms / max_ms | 3,000 / 5,000 |
log_retention_budget_bytes | 32 GiB |
log_retention_retry_spacing_secs | 15 |
log_retention_episode_max_secs / cooldown_secs | 1,800 / 1,800 |
The four log_retention_* settings bound follower catch-up log retention, which is always on. Every value must be positive. The defaults are sized for nodes with at least 200 GiB of disk; lower the budget on smaller disks. A budget above half of the data filesystem logs a startup warning.
Logging
RUST_LOG controls tracing output and defaults to info. Use warn for quieter operation or debug temporarily while diagnosing a problem.
Startup validation
Nexir rejects a memory plan that cannot fit, invalid addresses and modes, zero required limits, inconsistent global/per-connection budgets, request budgets below 60 MiB, invalid I/O queue sizes, unsafe snapshot limits, invalid Raft timing relationships, and missing or mismatched TLS files. It exits with a useful startup error rather than silently altering invalid settings.