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
| Flag | Default | Notes |
|---|---|---|
--listen ADDR | 127.0.0.1:4437 | TCP bind address for the HTTP + gRPC-Raft listener |
--core-count N | available_parallelism | Worker threads (each pinned to its mailbox event loop) |
--raft-group-count N | core_count × 16 | Total Raft groups. Higher = better stream-to-group hash spread |
--profile PROFILE | URSULA_PROFILE or default | Startup template: default, dev, tiny, small, standard, or large |
--storage-backend BACKEND | profile-selected | memory or disk |
--disk-path DIR | none | Selects disk storage when --storage-backend is omitted; Ursula stores Raft logs under DIR/raft-log |
--raft-node-id ID | none | Required for static gRPC cluster mode |
--raft-peer ID=URL | none | Static peer list (repeatable: one per node, including self) |
--raft-cluster-config FILE | none | JSON file equivalent to --raft-node-id + --raft-peer lines |
--raft-init-membership | off | One-time cluster-wide membership bootstrap (first start only) |
--raft-init-membership-per-group | off | Same, 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 input | Replacement |
|---|---|
--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.
| Profile | Intended use | Main defaults |
|---|---|---|
default, dev | Local development and backwards-compatible startup | Non-Raft default runtime; does not inject resource-budget env vars |
tiny | Memory-bound tests or very small nodes | Raft 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 |
small | Small nodes or cost-sensitive tests | Raft 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 |
standard | Production baseline | Raft 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 |
large | Larger nodes with more cache and write headroom | Raft 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:
| Variable | Required when | Notes |
|---|---|---|
URSULA_COLD_BACKEND | optional | s3 or memory. Default: no cold backend configured. Use memory only for local tests. |
URSULA_COLD_S3_BUCKET | BACKEND=s3 | Bucket name. |
URSULA_COLD_S3_REGION | BACKEND=s3 | AWS region. |
URSULA_COLD_S3_ENDPOINT | optional | Set for S3-compatible stores. |
URSULA_COLD_S3_ACCESS_KEY_ID, _SECRET_ACCESS_KEY, _SESSION_TOKEN | optional | Explicit credentials. Omit to use the AWS SDK credential chain. |
URSULA_COLD_ROOT | optional | Prefix for all cold and snapshot keys. Defaults to unprefixed. |
Flush and admission tuning
| Variable | Default | Purpose |
|---|---|---|
URSULA_COLD_FLUSH_INTERVAL_MS | 1000 | Background flush worker tick interval |
URSULA_COLD_FLUSH_BYTES | 8 MiB | Target bytes flushed per group per tick |
URSULA_COLD_FLUSH_MAX_CONCURRENCY | 4 | Parallel cold writes |
URSULA_COLD_MAX_HOT_BYTES_PER_GROUP | 64 MiB | Per-group hot ceiling - appends return 503 (cold backpressure) above this |
URSULA_LIVE_READ_MAX_WAITERS_PER_CORE | 65536 | Hard 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
| Variable | Purpose |
|---|---|
URSULA_TOKIO_CONSOLE | When 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_LOG | Standard 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.