Docs

Configuration

Configure LivenDB for your deployment environment.

LivenDB reads liven.toml (and optionally liven.conf) from the current working directory, or the file passed with --config / LIVEN_CONFIG. Relative paths inside that file (storage.data_directory and the ZTNA certificate paths) resolve against the config file's directory, not the process CWD. Environment variables prefixed with LIVEN_ or LIVENDB_ override file values, and the embedded API accepts a programmatic LivenConfig. The precedence is built-in defaults → config file → environment variables.

Configuration Structure

  • Server — network, ports, and connection settings
  • Storage — data directory, segment size, and fsync policy
  • Limits — streams, file descriptors, index budget, and scan limits
  • Security — auth mode, master key, and mTLS/ZTNA certificates

Server Configuration

OptionTypeDefaultDescription
environmentString"development"Deployment environment: development, test, or production
hostString"127.0.0.1"Bind address. In development/test the native listener is forced to 127.0.0.1.
db_portu1643121Native TCP protocol port
webui_portu1643120Web UI, REST, and WebSocket port
max_connectionsusize10000Concurrent native connections. Applied to the connection semaphore at startup and reported by status().
broadcast_capacityusize4096Live-subscription broadcast capacity. Applied at startup and reported by status().

Storage Configuration

OptionTypeDefaultDescription
data_directoryString"./data"Directory for .liven segment files
max_segment_size_mbusize10Segment rollover size. This is the key that is actually read; put it under [storage], not [limits].
sync_modeString"always"Only "always" is accepted: each flushed batch is fsynced before the write is acknowledged. Any other value makes the server refuse to start.

Limits Configuration

OptionTypeDefaultDescription
max_concurrent_streamsusize32Maximum number of concurrent data streams
max_open_file_descriptorsusize64Cached segment-file handles before eviction
max_index_ram_mbusizeautoPrimary-index budget. Auto-detected when absent; explicit 16 is treated as the legacy default and also auto-detects.
max_scan_resultsusize100000Caps live-key-index scans (stream scans without a limit). A live scan that would exceed the cap returns an error instead of silently truncating; historical (history()) and time-range scans are not capped.
index_high_water_percentu890Percentage of the index budget at which the high-water metric flips. Writes are still accepted until the hard limit.

limits.max_segment_size_mb is parsed but never read. Use storage.max_segment_size_mb instead.

Retention Configuration

OptionTypeDefaultDescription
default_max_age_secsu640Fallback max-age for streams without an override. 0 disables retention.
check_interval_secsu6460Background retention pass interval.
[retention.streams]tableemptyPer-stream max-age overrides in seconds, e.g. events = 3600.

Retention is segment-level: an inactive segment is deleted only when every live record in it is older than its stream's max-age. The active segment is left for rollover/compaction.

Security Configuration

OptionTypeDefaultDescription
modeString"auth_key"auth_key or none. Development/test auto-selects none only when security mode is not explicitly configured.
master_keyStringauto-generatedSeed for the first admin auth key. It is not a data-encryption key. Prefer LIVEN_SECURITY_MASTER_KEY.
ztna.enabledboolfalseEnable mTLS on the native TCP listener. Only takes effect whenenvironment is production; in development/test it is ignored and the listener stays cleartext.
ztna.cert_pathString"./certs/server.crt"Server certificate for mTLS
ztna.key_pathString"./certs/server.key"Server private key for mTLS
ztna.client_ca_pathString"./certs/ca.crt"Client CA used to verify peer certificates

security.auth_key.system_stream and security.auth_key.allow_local_auto_generation are currently parsed but not applied; the auth stream is hardcoded to auth_keys. mTLS covers the native TCP listener only — REST and WebSocket traffic remains HTTP.

Example Configuration File

[server]
environment = "production"
host = "0.0.0.0"
db_port = 43121
webui_port = 43120
[storage]
data_directory = "/var/lib/liven"
max_segment_size_mb = 256
sync_mode = "always"
[limits]
max_concurrent_streams = 64
max_open_file_descriptors = 128
max_index_ram_mb = 1024
max_scan_results = 500000
[security]
mode = "auth_key"
# master_key = "..." # prefer LIVEN_SECURITY_MASTER_KEY
[security.ztna]
enabled = false
# cert_path = "./certs/server.crt"
# key_path = "./certs/server.key"
# client_ca_path = "./certs/ca.crt"

Configuration Profiles

Development

[server]
environment = "development"
host = "127.0.0.1"
[security]
mode = "none"
[limits]
max_concurrent_streams = 16
max_open_file_descriptors = 32

Production

[server]
environment = "production"
host = "0.0.0.0"
[security]
mode = "auth_key"
[security.ztna]
enabled = true
cert_path = "/etc/liven/certs/server.crt"
key_path = "/etc/liven/certs/server.key"
client_ca_path = "/etc/liven/certs/ca.crt"
[limits]
max_concurrent_streams = 64
max_open_file_descriptors = 128
max_index_ram_mb = 1024
max_scan_results = 500000

Edge / Embedded

[limits]
max_concurrent_streams = 8
max_open_file_descriptors = 16
max_index_ram_mb = 32
max_scan_results = 10000

Index RAM Auto-Detection

When max_index_ram_mb is not explicitly set, Liven allocates 25% of detected host RAM, clamped to 32 MiB–4096 MiB. If detection fails, it falls back to 512 MiB. The 4 GiB value is an auto-detection ceiling, not a hard cap: an explicit larger value is accepted.

The limit is enforced against compound_key.len() + 128 bytes per live key: a 64-byte primary-index node and a 64-byte timestamp-index node. Allocator overhead and compaction scratch memory are still additional. Measured process RSS is roughly 157–192 bytes per key for the key lengths below.

Budget~8-byte key~32-byte key
16 MiB~107k keys~87k keys
64 MiB~427k keys~349k keys
256 MiB~1.7M keys~1.4M keys
1 GiB~6.8M keys~5.6M keys
4 GiB~27M keys~22M keys

On Linux, detection reads /proc/meminfo (host-visible memory), not cgroup limits. In containers, set max_index_ram_mb explicitly.

At the accounting limit, new keys are rejected with IndexRamLimitExceeded. There is no eviction or spill. A database whose rebuilt index exceeds a too-small limit still opens by default: Liven loads it, logs the overage, and rejects only new keys (overwrites, deletes, and reads continue). --strict-recoveryrefuses to open instead.

Monitoring

status() returns connection/subscriber counters plus index usage: max_connections, broadcast_capacity, active_connections, broadcast_subscribers, index_ram_bytes, index_ram_limit_bytes, index_high_water_bytes, and index_high_water_reached. Use process RSS for total process memory.

Best Practices

  • Set the index budget explicitly in containers — auto detection sees host RAM.
  • Keep keys short — key length and stream name are part of every index entry.
  • Use [storage] max_segment_size_mb — the duplicate under [limits] is ignored.
  • Use environment variables for secrets — set LIVEN_SECURITY_MASTER_KEY instead of committing it.
  • Restart after config changes — configuration is read at startup.
Note: a few options are parsed for forward compatibility but are not yet applied by the engine: limits.max_segment_size_mb, security.auth_key.system_stream, and security.auth_key.allow_local_auto_generation. The auth stream is hardcoded to auth_keys.