Skip to main content

Config file

By the end of this page you will have the complete list of every section and key ScramDB's TOML config file accepts, each with its type, real default, and effect, so you can look up any setting without guessing.

File format​

The config file is TOML. Every setting lives under a [section] table (or a nested [section.subsection] table); there is no flat top-level key. An unrecognized top-level key is a hard parse error naming the exact field, so a typo fails loud at startup rather than being silently ignored.

Two value grammars are reused across almost every section:

  • Byte sizes accept a plain integer (bytes) or a human-readable string: "4GB", "512MB", "768mb" (the suffix is case-insensitive), "1TB", "16KB". Recognized suffixes are B (or no suffix), KB/K, MB/M, GB/G, TB/T, PB/P, all 1024-based. An unrecognized suffix is a hard parse error naming it.
  • Durations accept a human-readable string ("30s", "5m", "200ms", "24h") or a plain integer of milliseconds.

A few fields use the string "auto" as a sentinel meaning "detect and size this automatically"; those are called out individually below.

Every section is optional. Omitting a section is byte-for-byte identical to writing that section out with every field at its default. The sections below are ordered the way a real config file reads top to bottom: general, storage and its sub-tables, JIT, GPU, UDF and its sub-tables, cluster and its sub-tables, then the query-execution sections.

[general]​

The one section that holds server-wide knobs with no home of their own; everything else lives under its own named section.

KeyTypeDefaultEffect
jit_enabledbooltrueEnable LLVM JIT compilation for hot bytecode regions.
metrics_portu169090Prometheus /metrics and plain /health HTTP port. 0 disables the server entirely. A CLI flag can override this; see Precedence.
pg_addressstring, host:portunset in the engine (falls back to the CLI flag's own default, 127.0.0.1:5432, loopback-only)The PostgreSQL wire-protocol listen address.
pg_no_authboolfalseDisables PostgreSQL client authentication entirely and ignores hba_file while it's on.
shutdown_drain_timeout_secsu64 (seconds)10Budget for active queries to finish during a graceful shutdown (SIGINT/SIGTERM).
shutdown_jit_quiesce_timeout_secsu64 (seconds)10Bound for waiting out an in-flight background JIT compile at shutdown.
hba_filestring (path)unsetPath to a pg_hba.conf-format access-control file. Unset uses the built-in default rules (localhost trusted, password elsewhere). Ignored entirely when pg_no_auth is set.
tls_certstring (path, PEM)unsetTLS certificate for the pgwire listener. Unset (either alone) means TLS is disabled (plaintext).
tls_keystring (path, PEM)unsetTLS private key. Must be set together with tls_cert to enable TLS.
license_keystringunset (Community edition)Enterprise or Trial license token. SCRAMDB_LICENSE_KEY takes precedence when both are set; see Environment Variables.

The 0.0.0.0:5432 binding you get from docker run scramdb/scramdb:latest comes from the Docker image's own startup command, not from ScramDB's own default, which is loopback-only. If you're running the binary directly and want it reachable from outside the host, set pg_address explicitly.

An unreadable hba_file, or a tls_cert/tls_key pair that can't be turned into a working TLS listener (unreadable file, bad format), is a fatal startup error, never a silent fallback to defaults or to plaintext.

[storage]​

Three fields have no default and must be set: prod_name (string), shard_id (a non-negative integer), and basedir (path). A config file that omits any of the three fails to parse.

KeyTypeDefaultEffect
data_dirpath{basedir}/data (derived if empty)Segment file directory.
buffer_pool_size_bytesbytes or string0 (unset sentinel, auto-sized from buffer_pool_percent of detected RAM, capped at buffer_pool_cap)Buffer pool size. A non-zero value pins an exact size and skips auto-sizing.
buffer_pool_percentu8, 1-10060Percent of detected RAM the auto-sizer targets when buffer_pool_size_bytes is 0.
buffer_pool_capbytes/string"64GB"Ceiling the auto-sizer never exceeds regardless of detected RAM.
memory_hard_limit_fractionf64, [0.1, 0.95]0.8Hard ceiling on process RSS as a fraction of detected RAM; a breach cancels active queries loudly.
execution_memory_bytesbytes/string"768MB"Per-query execution budget (hash tables, sorts, morsel buffers); a query over budget spills to temp_dir.
execution_memory_percentu8, 0-1000 (off; execution_memory_bytes governs)When above 0, wins over execution_memory_bytes, auto-sized from this percent of detected RAM, capped at execution_memory_cap.
execution_memory_capbytes/string"64GB"Ceiling for the execution-memory auto-sizer; only consulted when execution_memory_percent is above 0.
temp_dirpath{basedir}/spill (derived if empty)Spill-file directory.
segment_max_rowsu64131072Rows-per-segment rotation threshold.
flush_threshold_rowsusize8192Rows buffered per table before an active segment flushes. Must be at most segment_max_rows.
prefetch_depthusize8Pages the sequential-scan prefetch worker reads ahead. Must be at most prefetch_queue_depth.
prefetch_queue_depthusize64In-flight prefetch request queue depth.
bloom_max_bytesbytes/string"1KB"Max serialized bytes for one column's page-level Bloom filter.
wal_dirpath{data_dir}/wal (derived if empty)Write-ahead log directory.

[storage] also validates several cross-field constraints at config load and fails loud, naming the offending values, if any are violated: buffer_pool_percent and execution_memory_percent must be in range, flush_threshold_rows must not exceed segment_max_rows, prefetch_depth must not exceed prefetch_queue_depth, and if buffer_pool_size_bytes is set explicitly, buffer_pool_size_bytes + execution_memory_bytes must not exceed detected total RAM.

[storage.memory]​

Postgres-class per-component memory budgets. All sizes are byte strings.

KeyTypeDefaultEffectStatus
per_operator_bytesbytes/string"64MB"Intended budget per sort or hash operator (like work_mem).Not yet wired into query execution. Parses and validates; reserved for a future release.
maintenance_bytesbytes/string"256MB"ANALYZE / CREATE INDEX working-memory ceiling, reserved from the shared execution memory pool.Wired and enforced today.
hash_mem_multiplierf64, β‰₯ 1.02.0Intended multiplier on per_operator_bytes for a hash-based operator.Not yet wired.
working_set_bytesbytes/string0 (auto-sized from working_set_percent)Intended enforced running-set ceiling.Not yet wired.
working_set_percentu8, 1-10075Percent of RAM targeted when working_set_bytes is 0.
read_buffer_pool_bytesbytes/string"256MB"Hard cap on the page pool's total working set (checked out plus idle-recycled).Wired and enforced today: the pool backpressures rather than growing past it, and is raised automatically with a loud log line if configured below the deadlock-free floor implied by prefetch_depth.
effective_cache_bytesbytes/string0 (auto-sized from effective_cache_percent)Intended planner cost hint for how much of the working set is assumed page-cache-hot.Not yet wired into the planner.
effective_cache_percentu8, 1-10050Percent of RAM targeted when effective_cache_bytes is 0.

Set a *_bytes field to pin an exact value, or leave it at 0 to auto-size from the matching *_percent of detected RAM. The fields marked "not yet wired" parse, validate, and hold their configured value, but nothing in query execution reads them yet; treat them as reserved rather than as active tuning knobs.

[storage.io]​

KeyTypeDefaultEffect
backend"auto" | "file" | "io_uring" | "nvme_passthrough""auto""auto" and "file" both resolve to the always-safe direct-I/O backend (O_DIRECT reads and writes) today; "auto" doesn't yet pick io_uring automatically. "io_uring" is real and safe under concurrent workers. "nvme_passthrough" requires nvme_device and is validated present and usable at config-load time.
nvme_devicepath, optionalunsetThe exact NVMe character device (/dev/ngXnY) nvme_passthrough targets. Never auto-discovered: required, and probed, only when backend = "nvme_passthrough". A missing, wrong-type, or unusable device is a hard validation error naming the exact reason.

[storage.cold_config]​

Cold, object-store writeback for periodic full dumps. This is the one [storage] sub-table where defaulting works differently from every other one: omitting the whole table defaults every field together as a unit (the values in the Default column below); but once you write the table at all, every field in it is required, with no per-field fallback. Writing a partial [storage.cold_config] table produces a missing-field parse error rather than filling the rest in from defaults.

KeyTypeDefault (whole table omitted)Effect
cold_enablebooltrueIntended to enable periodic full dump to cold/object storage. Not active in the current build: whatever you set here is overwritten to false during startup, so the whole table is inert and no writeback ever runs. See the admonition below.
writeback_frequency_secsu64300Frequency of full dump to object store, in seconds.
concurrent_requestsusize100Concurrent requests against the cloud API.
bucket_namestring"tundra_cold"Destination bucket. Required non-empty once cold_enable = true.
cloud_api"GCP" | "AWS" | "Azure""GCP"Cloud API backend.
base_pathstring"snapshots"Base path within the bucket. Required non-empty once cold_enable = true.
Cold storage tiering is not available in the current build

The keys above are parsed and validated, but the cold tier is switched off unconditionally at startup: any cold_enable = true you write is reset to false before storage comes up, and there is no writeback or cold-read path behind it. Set the table however you like and nothing is written to object storage. This matches Storage Tiering, which documents the same limitation. Use backup and restore for durable off-box copies today.

[storage.wal]​

KeyTypeDefaultEffect
max_file_sizebytes/string"64MB"WAL file rotation size.
sync_every_writeboolfalsefsync after every append (per-commit durability, at a large latency cost) instead of relying on group-commit via epoch_duration.
epoch_durationduration"10ms"How often the flush worker batches and writes buffered WAL entries, even absent a size trigger. Must be greater than zero; a zero value would busy-spin the flush worker at 100% CPU.
flush_threshold_bytesbytes/string"64KB"Per-slot byte threshold that triggers an early flush ahead of the epoch timer.
synchronous_commitbooltrueWhether a transaction commit waits for its WAL entries to be durable before acknowledging the client. false acknowledges without waiting.

[storage.wal.archive]​

KeyTypeEngine defaultEffect
enabledboolfalseStarts the WAL archiver task, which ships closed segments to a destination for point-in-time recovery and branching. false costs nothing: no task is spawned.
destinationstring (URL or path), optionalunsetAccepts file:///abs/path, s3://bucket/prefix, gs://bucket/prefix, or az://account/container/prefix. If enabled = true and this is unset, it derives to a local {data_dir}/wal-archive, so PITR and branching work out of the box on a single node.
poll_intervalduration"5s"How often the archiver checks for newly closed segments once caught up. A backlog ships back-to-back with no added delay regardless of this setting.

The engine's own default for enabled is false. Separately, every config file ScramDB ships as a shipped reference or example explicitly sets enabled = true, so anyone starting from one of those files gets WAL archiving on. Both facts are true at once; they aren't the same thing.

In a cluster, leaving destination unset is safe for a single node but risky once there's more than one: each node's local {data_dir}/wal-archive is node-local, so an unset destination fragments PITR history across leader failovers. Set destination to shared or object storage for any real cluster. See Clustering.

[storage.wal.checkpoint]​

KeyTypeDefaultEffect
enabledboolfalseStarts a periodic checkpoint scheduler that fires on a time or WAL-bytes trigger, instead of only at graceful shutdown or a manual CHECKPOINT.
intervalduration"5m"Fire a checkpoint at least this often regardless of WAL volume.
wal_bytesbytes/string"1GB"Fire a checkpoint once accumulated WAL reaches this many bytes, even before interval elapses.

This is off by default in every shipped config, not only the engine default. Turning it on trades some background I/O for shorter recovery times; understand the tradeoff for your workload before enabling it in production, rather than flipping it on as a routine performance knob.

[storage.wal.retention]​

KeyTypeDefaultEffect
min_keptusize1Always keep at least this many closed WAL files, regardless of checkpoint coverage, archive state, or anchors.
archive_awarebooltrueOnce the archiver has started, a WAL file isn't droppable until the archiver's own watermark has passed it. false ignores archive state; only safe when point-in-time recovery via the archive isn't relied on.

[storage.wal.backup]​

KeyTypeDefaultEffect
destinationstring (URL or path), optionalunsetWhere a live instance finds its own base backup for from-timestamp branch materialization (CREATE DATABASE ... FROM ... AT TIMESTAMP and equivalent). Same accepted URL forms as [storage.wal.archive].destination. Unset means branch-from-timestamp refuses loudly, naming this exact key, rather than silently doing nothing.

[storage.gc]​

KeyTypeDefaultEffect
cycle_intervalduration"30s"Interval between MVCC garbage collection cycles.
max_cycle_durationduration"5s"Max duration for a single, time-bounded, incremental GC cycle.
max_snapshot_ageu64 (timestamp units, not wall-clock)300Max snapshot age before a transaction is excluded from the GC watermark; older transactions get a snapshot-too-old error rather than blocking cleanup indefinitely.

[storage.compaction]​

KeyTypeDefaultEffect
target_segment_rowsu641000000Target rows per compacted segment.
min_segments_to_mergeusize4Minimum frozen segments needed to trigger a merge.
delete_fraction_thresholdf640.3Maximum fraction of deleted rows a segment may hold before it's forced into compaction regardless of the other thresholds.
check_intervalduration"60s"Interval between compaction checks.

[jit]​

Compiled-artifact cache sizing.

KeyTypeDefaultEffect
compiled_cache_memorybytes/string"512MB"In-memory bound for compiled bytecode and JIT-tier kernels.
compiled_cache_diskbytes/string"1GB"On-disk bound for the cache's compiled-artifact files.

[gpu]​

GPU acceleration. This section is only present on builds compiled with GPU support; check with your build or image before relying on it being available in your deployment.

KeyTypeDefaultEffect
enabledbooltrueEnables GPU acceleration. Safe to leave on with no GPU hardware present: ScramDB detects the absence, logs one informational line, and falls back to CPU-only execution rather than failing to start.
device_idi320GPU device index. -1 auto-selects the device with the highest compute capability.
vram_budgetbytes/string or 00 (use 90% of free VRAM)Maximum VRAM budget.
vram_hash_table_budgetbytes/string or 00 (60% of vram_budget)VRAM reserved for hash table builds.
pinned_memory_poolbytes/string"256MB"Pinned host-memory pool size, used only as an automatic fallback when on-demand pinning fails. No capability flag or privileged mode is required for ScramDB to run with a GPU by default; raising this value is only relevant in the narrow case where the automatic pinned-pool fallback itself also fails to allocate.
streams_per_workeru322GPU streams per worker thread, for double-buffering.
min_batch_sizeu64 (rows)50000Minimum batch size eligible for GPU dispatch.
kernel_timeout_msu64 (ms)5000Kernel timeout. 0 disables it.
vendor"auto" | "nvidia" | "amd" | "apple""auto"Preferred GPU vendor.
arch_overridestring"" (auto-detect)Architecture override.
metrics_enabledbooltrueIntended to publish GPU metrics on the Prometheus /metrics endpoint. No observable effect today: the counters exist but nothing reads them onto /metrics, so leaving this true adds no GPU series to the endpoint. Consistent with GPU tuning and Observability.
debug_launchesboolfalseLogs every GPU kernel launch at debug level.

Every shipped example or Docker config that touches [gpu] at all sets only enabled = true and leaves everything else at its default. See GPU Acceleration for the full picture of what runs on a GPU and when.

[udf]​

The afterburner UDF runtime.

KeyTypeDefaultEffect
enabledbooltruefalse makes CREATE FUNCTION / INSTALL MODULE for afterburner languages fail loudly; the shared runtime is never built, so there's zero footprint when off.
fuel_per_batchu64, > 050000000Fuel budget per chunk invocation, used to bound runaway UDF execution. This is a placeholder value pending calibration, not a precisely tuned number; treat it as a coarse safety bound.
memory_bytesbytes/string, > 0"64MB"Per-invocation linear-memory cap; also the pooling allocator's per-instance hard cap.
timeout_msu64 (ms), > 01000Per-invocation wall-clock backstop. The underlying timer tick runs at a fixed 10ms granularity regardless of this value, so very small values won't get finer-grained enforcement than that.
output_bytesbytes/string, > 0"16MB"Per-invocation result-size ceiling.
engine_slack_bytesbytes/string"32MB"Sizing slack added over the measured engine-fixed memory footprint.
aot_cache_dirpath, optionalunset (derives to {basedir}/udf-cache)Intended on-disk ahead-of-time compile-cache root. Not read by any code today; reserved for a future release.
aot_cache_max_bytesbytes/string, > 0"512MB"Intended size bound for the AOT cache. Not read by any code today.
preinstall_dirstring (path)"/opt/scramdb/dist"Directory of curated packages installed automatically at startup, non-blocking, after the PostgreSQL listener is already up. Installation is idempotent across restarts. An empty string disables it. A host where this directory doesn't exist skips it silently, with only a debug-level log line.

[udf.registry]​

Governed access for name-form package install and upgrade.

KeyTypeDefaultEffect
urlstring (URL), validated"https://registry.afterburner.sh"Registry base URL for name-form install, upgrade, and version-listing calls.
token_filepath, optionalunset (anonymous access)Path to a bearer token file for authenticated registry calls, read fresh at each call. Never put the token inline in the TOML file. The file must be mode 0600 (not group or world readable); config validation fails loud, naming the exact mode found, if it isn't.
allowarray of glob strings["*"]Coordinate glob allow-list, checked before any network call.
denyarray of glob strings[]Coordinate glob deny-list, checked before allow; a match refuses loudly.
offlineboolfalsetrue makes every name-form install/upgrade/version verb fail loudly, naming this key, instead of making a network call. The bytes-upload install form always works regardless, since it performs no network call.
auto_update"off" | "check" | "apply""off""off": no ambient background task. "check": periodically resolves available upgrades into a view, but never applies them. "apply": additionally applies upgrades on the same cadence, honoring any version pins.
update_intervalduration, > 0 when auto_update isn't "off""24h"Cadence for the auto_update background task. Inert while auto_update = "off".

[udf.thrust]​

The governed worker pool UDF invocations run on.

KeyTypeDefaultEffect
enabledbooltruefalse runs scram.invoke / scram.invoke_batch inline on the calling task. true (the default) queues them onto this governed pool instead.
workersusize0 (auto: clamp(available_parallelism / 8, 1, 4))Pool worker count. This bounds isolation, not query throughput; query throughput comes from ordinary morsel fan-out, not from this pool.
nicei8, -20..=1919OS nice value for pool workers.
numa"auto" | "off""auto""auto" derives CPU pinning from real hardware topology, minus the cores reserved for query execution. "off" disables NUMA-aware pinning entirely (nice-value governance only).
affinityarray of core ids, optionalunset (auto-derive)Explicit CPU affinity mask, overriding numa-driven auto-derivation. Must be non-empty if set.
queue_depthusize0 (afterburner's own default of 256)Bounded work-queue depth for the pool.

[udf.daemon]​

Autostart for long-running packages. After the preinstall sweep, an installed package whose manifest declares [metadata.daemon] autostart = true and whose manifold grants listen is started in-process on the engine's own reactor, supervised, and surfaced in scram_daemons. The shipped consumer is scramdb/semantics, the Semantic AI MCP server on port 9191, which is why the release images publish that port. A distribution with no daemon-declaring package makes this a no-op scan.

KeyTypeDefaultEffect
enabledbooltrueMaster switch for the whole seam. false starts no daemons at all and logs the reason; nothing else about package installation changes.
shardsusize1Shards per daemon. Only HTTP daemons expand past 1.
env_allowlistarray of stringsPGHOST, PGPORT, PGUSER, PGPASSWORD, PGDATABASE, MCP_PORT, MCP_AUTH, SEMANTICS_MAX_ROWS, SEMANTICS_POOL_SIZE, SEMANTICS_MAX_CRED_POOLSProcess environment variables forwarded into daemon invocations. This is a ceiling, not a grant: the package's own manifold allowlist still decides what the script may actually read, so a variable must pass both to reach it.

A daemon that fails to start is a loud ERROR and a failed row in scram_daemons, never a wedged boot. A pool whose shards all die is restarted with bounded exponential backoff, base 2 seconds and doubling, up to 5 restarts; after that it stays failed with the reason rather than disappearing.

[cluster]​

Presence of a [cluster] table, even an empty one, activates cluster mode; absence is byte-identical to running as a single node.

A [cluster] table on a Community-edition node is a startup failure: ScramDB refuses to start the process at all unless the resolved license is Enterprise or Trial. This happens before any port is bound; it's a process exit, not a SQL-level error. See Clustering for the exact gate and how to supply a license.

KeyTypeDefaultEffect
node_namestring, optional, ≀ 255 bytesunset (falls back to the OS hostname)This node's stable name.
cluster_listenhost:port"0.0.0.0:7190"Address this node's cluster transport listens on.
advertise_addrstring (host:port or DNS name), optionalunset (auto-detected from the first non-loopback interface plus cluster_listen's port)Address other nodes dial to reach this node. Always set this explicitly behind NAT or in a container network.
seedsarray of host:port strings[]Static seed peers. Empty means a cluster-of-one: a fully functional single-node cluster with zero distributed overhead.
bootstrap_expectu32, optionalunset (seeds.len() decides)Seedless formation: how many other voter-role nodes must connect before this node founds the cluster, so a Helm chart or other zero-seed deployment can bring up every replica waiting on the same count instead of a static peer list. 0 founds a cluster of one. Refused at boot if it disagrees with a non-empty seeds list, or if it's positive with no seeds and no address-capable discovery provider (dns with dns_name set, or swim) that could ever supply the peers.
regionstring, optionalunset (regionless)This node's home region. When set, a table homed in this region keeps all of its voters here, so its transactions commit at region-local quorum latency instead of crossing the WAN. Advertised to peers and visible in scram.nodes. An empty or whitespace-only value counts as unset, never a region literally named "".
zonestring, optionalunsetA finer failure domain inside region (rack or availability zone). Reported in scram.nodes alongside region; placement treats it as informational today rather than a hard constraint.
columnar_replicaboolfalsetrue makes this voter also mirror every committed entry of the groups it owns into a full local columnar store, so whole-statement analytics run locally with zero network hops, while it keeps its normal bucket ownership. Costs one full columnar copy on this node plus a second apply per committed entry. Mutually exclusive with learner = true; the combination is refused at boot.
learnerboolfalsetrue makes this a read-replica-only (columnar learner) node: it hosts learner groups only, owns no buckets, and is never promoted to a voting member.
discoveryarray of "static", "dns", "swim"["static", "dns", "swim"]Active peer-discovery providers. An unrecognized name is a hard validation error.
dns_namestring, optionalunsetHeadless-service DNS name for the "dns" discovery provider. Required (and validated) when discovery includes "dns".
dns_refreshduration, > 0"5s"How often the "dns" provider re-resolves dns_name.
swim_gossip_fanoutusize3Live members the SWIM protocol broadcasts a direct gossip message to every tick, on top of probe piggyback. 0 disables the extra fan-out.
replication_factoru32, β‰₯ 1 (and ≀ cluster size once seeds is non-empty)3Replication factor for shard groups.
tls_cert, tls_key, tls_capath, optional (all three together, or all omitted)unsetOptional mutual TLS between cluster nodes. Independent of pgwire's own [general] tls_cert / tls_key.
connect_backoff_minduration, > 0 (and ≀ connect_backoff_max)"200ms"Minimum reconnect backoff.
connect_backoff_maxduration"10s"Maximum reconnect backoff.
send_queue_bytesbytes/string, β‰₯ 1"64MB"Byte bound on each peer connection's outbound send queue (credit-based backpressure).
recv_queue_bytesbytes/string, β‰₯ 1"64MB"Byte bound on the manager-wide inbound fan-in queue.
tso_batchu64, β‰₯ 1262144Batched logical-timestamp allocation size.
group0_bootstrap_timeoutduration, > 0"60s"How long a node waits at bootstrap for every configured seed to connect before forming the metadata group. Never falls back to a partial voter set on expiry; startup fails loud instead.
default_bucketsu32, β‰₯ 18Shard buckets a new primary-key table is auto-assigned at CREATE TABLE.
txn_lock_ttlduration, > 0"10s"Lease duration on a distributed transaction's locks.
commit_v2boolfalseEnables a single-group commit path for transactions confined to one shard group. Off by default; this is a correctness-gated optimization, not a routine tuning knob.

cluster_listen defaults to port 7190. Point-to-point cluster transport and the pgwire client port are separate listeners entirely.

Cluster sub-tables​

Five more sub-tables exist under [cluster] for fine-grained tuning of the underlying protocols. Each follows the same "absent table = every field at its default, byte-identical" contract as every section above, and each field has its own default, so writing only some of them leaves the rest untouched.

None of the five need to be set for a cluster to run correctly. They exist for operators tuning failure-detection sensitivity or protocol timing under specific network conditions, and getting failure-detector timing wrong in either direction, too twitchy or too slow, has real availability consequences. Every field is listed below with its real default so you can reason about the tradeoff instead of guessing.

[cluster.swim]​

Failure detection: how fast a dead peer is noticed, and how hard the cluster tries not to be wrong about it.

KeyTypeDefaultEffect
ping_timeoutduration"500ms"Bound on a direct Ping's Ack before escalating to indirect probing. Lower = faster detection, at the cost of more false Suspect escalations on a slow-but-alive peer.
indirect_timeoutduration"500ms"Bound on an indirect (PingReq-relayed) probe before declaring Suspect.
indirect_probe_countinteger3Random relays asked to indirectly probe a non-responding target. Higher = more confidence before Suspect, at the cost of more probe traffic per suspected failure.
suspicion_minduration"1s"Floor of the dynamic suspicion timeout, reached at maximal corroboration. Lower = faster Dead declaration once every peer agrees, at the cost of a shorter window to catch a false positive.
suspicion_maxduration"5s"Ceiling of the dynamic suspicion timeout, used when no peer has corroborated yet.
dead_tombstoneduration"30s"How long a Dead member is retained before being reaped. A rejoin inside this window resumes at a fresh incarnation instead of a brand new join.
max_piggyback_updatesinteger6Cap on membership updates piggybacked per outbound message. Higher = faster dissemination per message, at the cost of larger frames.
retransmit_multiplierinteger4Multiplier in the retransmit-limit formula lambda * ceil(log2(n + 1)). Higher = more redundant retransmission of each update, so more reliable dissemination for more gossip traffic.
gossip_fanoutinteger3No effect here. This node always takes its fan-out from swim_gossip_fanout in [cluster] instead. Kept as a real field so the table still round-trips, not a live knob.
max_healthinteger8Ceiling of the local-health counter (Lifeguard LHM). Higher = more headroom to distinguish "very healthy" from "somewhat healthy" before probe timeouts stop scaling.
max_health_multiplierfloat4.0Timeout multiplier applied at maximum local health. Higher = more tolerance for a node under heavy local load before it starts falsely suspecting peers.
protocol_periodduration"1s"How often the SWIM driver's tick fires (probe, suspicion and reap pacing), independent of the timeouts above. Lower = faster detection and dissemination, at the cost of more background probe traffic.

[cluster.consensus]​

One instance, shared by the metadata group and every per-shard replication group.

KeyTypeDefaultEffect
election_timeout_minduration"1s"Lower bound of the randomized election and pre-vote timeout. Lower = faster failover after a leader crash, at the cost of more spurious elections under network jitter. See the warning below before lowering this.
election_timeout_maxduration"2s"Upper bound of the same randomized timeout. The randomized spread between min and max is what avoids split votes.
heartbeat_intervalduration"50ms"The leader's steady-state heartbeat and AppendEntries broadcast period. Lower = fresher followers and faster leader-loss detection, at the cost of more replication traffic at idle.
max_entries_per_appendinteger64Cap on log entries sent in one AppendEntries. Higher = fewer round trips to catch a lagging follower up, at the cost of larger per-message payloads.
max_append_bytesbyteshalf of [cluster.transport] max_frame_size, so 8MB at that key's own defaultByte cap on one AppendEntries payload, applied alongside the entry-count cap above. Derived from the frame cap rather than set independently, so the two can never disagree. Validated at boot against that derived ceiling.
max_pending_readsinteger1000Cap on concurrently outstanding read-index requests. Bounds memory on a leader that is stuck unable to reach a quorum, rather than letting it grow unbounded.
Do not lower the election window without reading this

The election defaults are not conservative by accident. An earlier 150ms default caused election churn whenever synchronous applies starved the IO runtime, which turns a busy cluster into a leaderless one exactly when it is under load. Raise these values for WAN distances; lower them only with measurements in hand.

[cluster.consensus] was named [cluster.raft] before this release. The old spelling stays accepted forever as an alias, so a config file written against any earlier release keeps working with zero edits. The new name is deliberately algorithm-neutral: every knob in this table is a property of leader-based replication in general, not of one specific consensus protocol, so a future change to the algorithm underneath ScramDB never forces you to rewrite this file. That is a compatibility promise: [cluster.raft] keeps working in every future release, full stop.

[cluster.rebalance]​

How quickly shard-group membership converges after a topology change.

KeyTypeDefaultEffect
catch_up_graceduration"200ms"Grace period after a learner is added before the driver tries to promote it. Lower = faster promotion, at the risk of promoting a learner that has not genuinely caught up. This is a bounded-wait heuristic, not a proof of catch-up.
retry_backoff_minduration"20ms"Floor of the retry backoff after a transient membership-change failure.
retry_backoff_maxduration"2s"Ceiling of that retry backoff.
reconcile_intervalduration"200ms"How often the periodic reconciler re-derives and converges each owned and led group's membership. Lower = a designated learner is added sooner after a table is created, at the cost of more frequent passes (cheap, and a no-op once converged). Must be greater than zero; 0 is rejected loudly at boot rather than panicking later.

[cluster.txn]​

KeyTypeDefaultEffect
version_windowinteger8Committed versions retained per key on each shard's transaction automaton. Higher = a longer window of point-in-time reads stays answerable, so fewer snapshot-too-old errors, at the cost of more per-key memory in the shard's in-memory write history.

[cluster.transport]​

Connection establishment between nodes.

KeyTypeDefaultEffect
handshake_timeoutduration"10s"Bound on the Hello and HelloAck round trip, and on the whole TLS-accept-plus-handshake span. Shorter frees a stuck handshake's slot sooner, at the risk of a false timeout under real load.
max_pending_handshakesinteger256Cap on concurrently in-progress inbound handshake attempts. Higher rides out a bigger connection burst, at the cost of more concurrent in-flight handshake buffers and tasks.
max_frame_sizebytes"16MB"Cap on a single wire frame's payload. Higher allows a bigger single payload and fewer application-level fragments, at the cost of a bigger worst-case single-frame buffer. [cluster.consensus] max_append_bytes derives from this value.

A complete, working example that sets [cluster]'s core fields, though not these five sub-tables, ships inside the Docker image itself; see Start from the shipped example for the exact path, how to pull it out and edit it, and a pointer to a larger annotated example that does cover them.

[execution]​

KeyTypeDefaultEffect
workers"auto" or a positive integer"auto" (every core the process can see)Core-pinned workers a query's morsel scheduling dispatches across. An explicit count caps dispatch. 0 or a negative value is a hard parse-time rejection, not a silent clamp to 1.
morsel_sizebytes/string"4MB"Target bytes per morsel for byte-size-aware table scans.
transactional_morsel_thresholdusize, 1-644HTAP dispatch classifier: a statement dispatching this many morsels or fewer, or any DML statement, classifies as transactional and rides the scheduler's priority lane, dequeued ahead of analytical work, so a short OLTP-style statement no longer waits behind a whole analytical query. An out-of-range value is a hard startup error naming the accepted range, never a silent clamp.
aging_promotion_msu64 (milliseconds), 1-100010HTAP starvation ceiling: analytical work waiting longer than this is served ahead of further transactional work, so a starved analytical task is guaranteed service within this window even under a sustained flood of short statements. Same startup validation as transactional_morsel_threshold.
copy_batch_rowsusize65536Rows buffered per COPY FROM batch before insertion.
copy_pipeline_depthusize, β‰₯ 14Parsed COPY batches buffered ahead of insertion.
max_recursive_iterationsusize1000Fixpoint iteration cap for a recursive CTE before it's treated as non-terminating.
exchange_recv_timeoutduration"30s"How long a distributed exchange-receive source waits for producers before failing loud.
exchange_channel_capacityusize32Decoded chunks an exchange receiver buffers before backpressure.
spill_agg_partitionsusize, β‰₯ 164Partitions for spill-to-disk hash aggregation.
grace_join_min_partitionsusize, β‰₯ 1 and ≀ grace_join_max_partitions16Floor of the adaptive Grace hash join partition count.
grace_join_max_partitionsusize256Ceiling of the adaptive Grace hash join partition count.
join_bloom_thresholdusize, β‰₯ 11024Minimum build-side rows before a hash join builds a Bloom pre-filter.
parallel_build_thresholdusize10000Minimum build-side rows before a hash join build parallelizes across threads.
runtime_filtersbooltrueEnables sideways information passing: a selective hash-join build side's Bloom filter prunes the probe-side scan. Disabling it only removes the pruning; results are unchanged either way.
arena_chunk_sizebytes/string, β‰₯ 1"2MB"Chunk size for the per-query bump allocator.
sequence_reservation_blockusize32Values a sequence durably reserves ahead of use; a restart may skip up to this many values.
jit_prefetch_distanceu648Rows ahead the compiled kernels software-prefetch hash-table buckets. The effective distance is additionally clamped by a fill-buffer budget model, so a kernel prefetching several streams at once cannot stall the core by exhausting its L1 fill buffers; raising this past what the budget allows changes nothing. 0 disables prefetch emission entirely. Read at code-generation time, so it applies to kernels compiled after the change.
jit_compile_threadsusize, clamped to 1-83Size of the background compile pool. At the default, the tier ladders of different queries compile in parallel instead of queueing behind one worker, which is what keeps a freshly seen query shape from running interpreted while a backlog drains. Each worker carries a 16 MiB stack and compiles are CPU-bound, so a large pool just steals cores from query workers. Set 1 to restore strict single-threaded compilation as a rollback lever.

[aqe]​

Adaptive Query Execution, for distributed shuffle joins. Parsed and validated on a single node too, but inert without a [cluster] and a shuffle join in play.

KeyTypeDefaultEffect
coalesce_targetbytes/string, β‰₯ 1"64MB"Target bytes for one coalesced shuffle-join consumer read.
skew_factoru64, β‰₯ 15A partition is flagged as skewed when its bytes exceed this multiple of the median.
skew_minbytes/string, β‰₯ 1 and β‰₯ coalesce_target"256MB"Absolute floor a partition must also exceed to be flagged as skewed.
consumer_attemptsu32, β‰₯ 13Bounded re-dispatch attempts for a materialized consumer fragment before failing loud.
straggler_backup_delayduration, > 0"2s"How long a fragment may run before a speculative backup is dispatched elsewhere.
runtime_filter_max_keysusize, β‰₯ 1262144Broadcast-join small-side row budget past which the runtime Bloom filter is skipped.

[statistics]​

Automatic statistics collection for the query planner.

KeyTypeDefaultEffect
auto_analyze_check_intervalduration, > 0"120s"Interval between auto-analyze cycles.
auto_analyze_staleness_ratiof64, > 00.10Re-analyze a table once its row count has drifted by more than this fraction since the last analysis.
auto_analyze_sample_pagesusize, β‰₯ 164Max pages sampled per table when building histograms and most-common-value lists.
mcv_entriesusize, β‰₯ 1100Max most-common-value entries retained per column.
column_pairsusize, β‰₯ 150Max column pairs tracked for multi-column statistics per table.
analyze_on_loadbooltrueTrigger an immediate full ANALYZE on COPY or bulk-INSERT completion, instead of waiting for the next staleness sweep.

[optimizer]​

Join-ordering search limits.

KeyTypeDefaultEffect
dp_table_limitusize, β‰₯ 112Base relation count at or below which join ordering runs the exact dynamic-programming search; above it, a greedy fallback orders the join instead.
cascades_budget_factoru64, β‰₯ 1500Cascades iteration budget multiplier: max_iterations = num_tables^2 * this.

[oltp]​

KeyTypeDefaultEffect
point_fast_pathbooltrueClassifies and inline-executes an eligible single-table index-equality SELECT / UPDATE / DELETE, or a single-row literal INSERT, bypassing planning, bytecode compilation, and the pipeline scheduler. A pure latency optimization: turning it off, or a statement that doesn't classify, changes nothing about the result.

[resilience]​

Client liveness checks, statement and session timeouts, and the connection-pool watchdog.

KeyTypeDefaultEffect
client_liveness_check_intervalduration"2s"Cadence of the non-blocking peer-liveness probe. "0" disables the probe entirely; that's an intentional off switch, not an error.
statement_timeoutduration"0" (disabled)Server-wide default: cancels a running statement past this duration. SET statement_timeout = ... overrides it per-session, live, with no restart. Matches PostgreSQL's own default of off.
idle_in_transaction_session_timeoutduration"0" (disabled)Rolls back and closes a session that's been idle inside an open transaction (including an aborted one) past this duration. Matches PostgreSQL's own default.
transaction_timeoutduration"0" (disabled)Rolls back and closes any one transaction, running or idle, once it's been open this long. Matches PostgreSQL 17's transaction_timeout.
tcp_keepalivebooltrueOS-level TCP keepalives on every accepted pgwire socket.
tcp_keepalive_idleduration"60s"Idle time before the OS sends the first TCP keepalive probe.
enabledbooltrueMaster switch for this section's connection-pool watchdog.
watchdog_enabledbooltrueKill switch for just the pool watchdog's observer thread.
cadence_floorduration, > 0"100us"Fastest pool-watchdog sampling cadence.
cadence_capduration, β‰₯ cadence_floor"10ms"Slowest pool-watchdog sampling cadence.
  • Configuration Reference - how these sections and the other two config surfaces fit together.
  • Environment Variables - the canonical list of env vars that exist outside this file.
  • Precedence - which of the config file, a CLI flag, or an env var wins for the handful of settings more than one of them can touch.