Configuration

Ursula is configured via CLI flags and environment variables. There is no TOML or YAML configuration file today.

defaults < environment variables < CLI flags

CLI flags

FlagDefaultNotes
--listen ADDR127.0.0.1:4437TCP bind address for the HTTP + gRPC-Raft listener
--core-count Navailable_parallelismWorker threads (each pinned to its mailbox event loop)
--raft-group-count Ncore_count × 16Total Raft groups. Higher = better stream-to-group hash spread
--profile PROFILEURSULA_PROFILE or defaultStartup template: default, dev, tiny, small, standard, or large
--storage-backend BACKENDprofile-selectedmemory or disk
--disk-path DIRnoneSelects disk storage when --storage-backend is omitted; Ursula stores Raft logs under DIR/raft-log
--raft-node-id IDnoneRequired for static gRPC cluster mode
--raft-peer ID=URLnoneStatic peer list (repeatable: one per node, including self)
--raft-cluster-config FILEnoneJSON file equivalent to --raft-node-id + --raft-peer lines
--raft-init-membershipoffOne-time cluster-wide membership bootstrap (first start only)
--raft-init-membership-per-groupoffSame, but bootstrap each Raft group independently

memory uses an in-memory Raft log. disk uses the durable OpenRaft log store and works for both single-node and static gRPC cluster runs. When --storage-backend is omitted, --disk-path DIR selects disk storage automatically.

Legacy storage aliases

These compatibility aliases are hidden from CLI help and will be removed in a future 0.1.x cleanup:

Legacy inputReplacement
--raft-memory--storage-backend memory
--raft-log-dir DIR--storage-backend disk --disk-path DIR
--storage-dir DIR--disk-path DIR
--storage-backend raft-log--storage-backend disk

--wal-dir DIR is also still accepted for the old standalone diagnostic WAL runtime, but it is not a supported production storage path. Use --storage-backend disk --disk-path DIR for durable storage.

Resource profiles

--profile and URSULA_PROFILE expand to a startup template. They set resource-budget env defaults and, when no storage backend is explicit, choose the storage shape: default/dev keep the lightweight non-Raft default runtime; tiny, small, standard, and large default to Raft memory. Supplying --disk-path DIR upgrades any profile to disk storage under DIR/raft-log. Explicit storage flags still win, and CLI admission flags such as --http-inflight-body-bytes still win over profile defaults.

ProfileIntended useMain defaults
default, devLocal development and backwards-compatible startupNon-Raft default runtime; does not inject resource-budget env vars
tinyMemory-bound tests or very small nodesRaft memory by default; 64 MiB cold cache, 4 MiB cold flushes, 2 cold writes, 8 MiB hot/admission Raft caps, 64 MiB HTTP in-flight body budget
smallSmall nodes or cost-sensitive testsRaft memory by default; 64 MiB cold cache, 4 MiB cold flushes, 2 cold writes, 16 MiB hot/admission Raft caps, 64 MiB HTTP in-flight body budget
standardProduction baselineRaft memory by default; 256 MiB cold cache, 8 MiB cold flushes, 4 cold writes, 64 MiB hot/admission Raft caps, 256 MiB HTTP in-flight body budget
largeLarger nodes with more cache and write headroomRaft memory by default; 512 MiB cold cache, 16 MiB cold flushes, 8 cold writes, 128 MiB hot/admission Raft caps, 512 MiB HTTP in-flight body budget

Chaos deployments should use --profile tiny plus deployment-level env overrides such as URSULA_NODE_MEMORY_ABORT_CAP_BYTES; chaos-only safety limits are not part of the server profile list.

Cluster config file

The --raft-cluster-config FILE JSON shape:

{
  "node_id": 1,
  "init_membership_per_group": true,
  "peers": [
    {"node_id": 1, "url": "http://10.0.0.1:4437"},
    {"node_id": 2, "url": "http://10.0.0.2:4437"},
    {"node_id": 3, "url": "http://10.0.0.3:4437"}
  ]
}

Same file on every host. Only node_id at the top level changes.

Cold storage environment variables

Cold backend is selected entirely via URSULA_COLD_* env vars. See Configure S3 for the full reference. Minimum set:

VariableRequired whenNotes
URSULA_COLD_BACKENDoptionals3 or memory. Default: no cold backend configured. Use memory only for local tests.
URSULA_COLD_S3_BUCKETBACKEND=s3Bucket name.
URSULA_COLD_S3_REGIONBACKEND=s3AWS region.
URSULA_COLD_S3_ENDPOINToptionalSet for S3-compatible stores.
URSULA_COLD_S3_ACCESS_KEY_ID, _SECRET_ACCESS_KEY, _SESSION_TOKENoptionalExplicit credentials. Omit to use the AWS SDK credential chain.
URSULA_COLD_ROOToptionalPrefix for all cold and snapshot keys. Defaults to unprefixed.

Flush and admission tuning

VariableDefaultPurpose
URSULA_COLD_FLUSH_INTERVAL_MS1000Background flush worker tick interval
URSULA_COLD_FLUSH_BYTES8 MiBTarget bytes flushed per group per tick
URSULA_COLD_FLUSH_MAX_CONCURRENCY4Parallel cold writes
URSULA_COLD_MAX_HOT_BYTES_PER_GROUP64 MiBPer-group hot ceiling - appends return 503 (cold backpressure) above this
URSULA_LIVE_READ_MAX_WAITERS_PER_CORE65536Hard cap on SSE waiters held per core

URSULA_COLD_FLUSH_MIN_HOT_BYTES and URSULA_COLD_FLUSH_MAX_BYTES are still accepted as advanced overrides, but most deployments should use URSULA_COLD_FLUSH_BYTES.

Diagnostic

VariablePurpose
URSULA_TOKIO_CONSOLEWhen set, initializes the Tokio console subscriber if the binary was built with --features tokio-console and RUSTFLAGS="--cfg tokio_unstable"; otherwise logs a warning
RUST_LOGStandard tracing subscriber filter ursula=info,ursula_runtime=info,ursula_raft=info is a reasonable baseline

Minimal examples

In-memory single node:

ursula \
  --listen 127.0.0.1:4437 \
  --core-count 4 \
  --raft-group-count 64 \
  --storage-backend memory

Disk-backed single node:

ursula \
  --listen 127.0.0.1:4437 \
  --core-count 4 \
  --raft-group-count 64 \
  --storage-backend disk \
  --disk-path ./data

Three-node durable cluster (same command on each host, node_id from the cluster config):

URSULA_COLD_BACKEND=s3 \
URSULA_COLD_S3_BUCKET=my-ursula-bucket \
URSULA_COLD_S3_REGION=us-east-1 \
ursula \
  --listen 0.0.0.0:4437 \
  --core-count 16 \
  --raft-group-count 256 \
  --storage-backend disk \
  --disk-path /var/lib/ursula \
  --raft-cluster-config /etc/ursula/cluster.json

See Deploy a cluster for the full walk-through and Configure S3 for cold-tier specifics.