Vole can be configured with CLI flags, a config file, or a mix of both. CLI flags always take priority over the config file, so you can set your baseline in the file and override individual settings on the fly.
A handful of settings can also be changed at runtime with CONFIG SET without restarting.
Copy the example and edit it:
cp vole.conf.example /etc/vole/vole.confThen start Vole with:
vole --config /etc/vole/vole.confThe format is one setting per line: key value. Lines starting with # are comments. See vole.conf.example in the repo for a fully commented template.
You can still pass CLI flags alongside --config. If a flag shows up in both places, the CLI wins.
This page walks through each setting, explains what it does, and tells you when you'd actually want to change it.
Default: 127.0.0.1:7379
The address Vole listens on for RESP connections. This is the main protocol -- it's what vole-cli and every compatible client library connects to.
If you only need local access, the default is fine. To accept connections from other machines:
vole --addr 0.0.0.0:7379To run on a non-standard port:
vole --addr 0.0.0.0:6400Default: disabled
Turns on the HTTP/JSON API. Omit this flag when you want to run only the RESP server.
vole --http-addr :8080This gives you REST endpoints for all operations, a Prometheus metrics endpoint at /metrics, a health check at /health, and Server-Sent Events for real-time key change notifications at /api/v1/events. The metrics endpoint includes command counters, per-command latency totals, memory and GC stats, eviction count, lazy-free queue depth, and store lock wait time.
You can run this on the same machine as the RESP port without issues -- they're independent listeners.
Vole stores everything in memory, but it can write data to disk so it comes back after a restart. You've got two options, and they work well together.
Default: true
When this is on, every write command gets appended to a log file before the client gets a response. On restart, the log is replayed to rebuild the dataset.
When Vole rewrites the AOF to compact it, the rewritten file carries the current dataset for core Redis types and Vole's extended types: streams and consumer groups, JSON documents, time-series data, reliable queues, tags, delayed-key metadata, HyperLogLog state, and multi-master conflict metadata.
If you're using Vole as a pure cache and don't care about surviving restarts, turn it off:
vole --appendonly=falseDefault: vole.aof
Where the append-only log goes. Can be a relative or absolute path.
vole --appendfilename /var/lib/vole/data.aofDefault: everysec
How often the AOF is flushed to disk. This is the classic durability-vs-speed tradeoff.
| Value | What it means | When to use it |
|---|---|---|
always |
Flush after every write | Choose this when every acknowledged command must survive a crash. This is the slowest option. |
everysec |
Flush once a second | Good balance for most workloads. You might lose up to one second of writes in a hard crash. |
no |
Let the OS decide | Fastest. The OS will flush eventually, but you could lose more data in a crash. Fine for caches. |
vole --appendfsync alwaysDefault: vole.rdb.json
Path for point-in-time snapshots. A snapshot is a full dump of everything in memory, written as JSON.
Snapshots are useful because replaying a long AOF can be slow on restart. With both enabled, Vole loads the snapshot first (fast) and then replays only the AOF entries that came after it.
Default: 0 (disabled)
How often to take automatic snapshots. Set this to something like 5m or 1h. When a snapshot completes, the AOF is truncated since everything in it is now captured in the snapshot.
vole --snapshot /var/lib/vole/vole.snap --snapshot-interval 5mYou can also trigger snapshots manually with the SAVE (blocking) or BGSAVE (background) commands.
On startup, Vole does this:
- If a snapshot file exists, load it.
- If an AOF file exists, replay it on top of the snapshot.
On each automatic snapshot:
- Write the snapshot to a temporary file, then rename it into place (atomic on most filesystems).
- Truncate the AOF.
So even if Vole crashes mid-snapshot, the old snapshot and AOF are still intact. You'll never end up with a half-written snapshot and a truncated AOF.
Default: 0 (unlimited)
A soft memory limit in bytes. When Vole estimates it's using more than this, it starts evicting keys according to the policy.
vole --maxmemory 536870912 # 512 MBThe estimate is still approximate because Go does not expose exact retained bytes for every object, but Vole now keeps the estimate per key and updates it when data changes. That keeps eviction decisions current without periodically walking the full keyspace.
You can change this at runtime:
CONFIG SET maxmemory 1073741824
Default: noeviction
What happens when the memory limit is hit.
| Policy | What it does |
|---|---|
noeviction |
Reject writes with an OOM error. Reads still work. |
allkeys-random |
Pick a random key and delete it. Any key is fair game. |
volatile-random |
Same, but only picks from keys that have a TTL set. If no keys have a TTL, writes fail. |
allkeys-lru |
Delete the key that was accessed least recently. Vole samples 5 random keys and evicts the oldest one, so it's an approximation. |
vole --maxmemory 536870912 --maxmemory-policy allkeys-lruAlso changeable at runtime:
CONFIG SET maxmemory-policy allkeys-lru
Default: none
Sets a password that clients must provide before they can run commands.
vole --requirepass s3cretOn the client side:
vole-cli
127.0.0.1:7379> GET foo
(error) NOAUTH Authentication required.
127.0.0.1:7379> AUTH s3cret
OK
127.0.0.1:7379> GET foo
"bar"
PING works without authenticating, so health checks still function. Everything else is blocked.
This is a single shared password, not per-user accounts. It's meant to keep casual access out, not to implement fine-grained permissions.
Default: none
Encrypt all traffic (RESP and HTTP) with TLS.
vole --tls-cert /etc/vole/cert.pem --tls-key /etc/vole/key.pemUse both flags together. The minimum TLS version is 1.2.
If you need a quick self-signed cert for testing:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
-subj '/CN=localhost'In production, use certs from your CA or Let's Encrypt. After rotating certs, restart the server so new connections use the updated files.
Default: none
Starts this instance as a follower of another Vole server. On startup, it connects to the leader, downloads a full snapshot, and then streams every subsequent write in real time.
# The leader
vole --addr :7379
# A follower
vole --addr :7380 --replicaof localhost:7379The follower is read-only. Writes get rejected with READONLY. You can manage replication from the CLI:
# Start following
vole-cli REPLICAOF localhost 7379
# Check status
vole-cli INFO
# Promote to standalone
vole-cli REPLICAOF NO ONE
# Or enable multi-master so both nodes accept writes
vole-cli MULTIMASTER ENABLE
vole-cli MULTIMASTER STATUSOr start following from the CLI:
REPLICAOF localhost 7379
A few things to be aware of:
- Replication is asynchronous. A write that succeeds on the leader might not have reached the follower yet.
- If the follower disconnects and reconnects, it resumes from the leader's replication backlog when the missing offset range is still available. If not, it falls back to a fresh snapshot.
- Failover can be coordinated through the cluster failover commands. During failover, epoch fencing prevents stale leaders from continuing to accept writes.
Default: auto-generated from a random value
A stable identifier for this node in a cluster. Set this explicitly for cluster deployments so the same node keeps the same identity across restarts.
For any cluster setup, set this explicitly:
vole --node-id node1 --addr :7379Default: none
A comma-separated list of other nodes in the cluster, in the format nodeID@host:port.
vole --node-id node1 --addr :7379 --peers "node2@host2:7380,node3@host3:7381"On startup, Vole divides 16,384 hash slots evenly across all known nodes (including itself). When a command targets a key that belongs to a different node, the client gets a MOVED redirect telling it where to go.
You can also add and remove nodes at runtime:
CLUSTER MEET host2:7380
CLUSTER FORGET <node-id>
Default: false
Turns on multi-master replication. Every node in the cluster accepts writes, and changes propagate to all peers automatically.
vole --addr :7379 --node-id node1 --peers "node2@localhost:7380" --multimasterWhen enabled, Vole connects to every known peer and sets up bidirectional write streaming. If a new node is added via CLUSTER MEET, it's automatically connected.
You can also toggle it at runtime:
MULTIMASTER ENABLE
MULTIMASTER DISABLE
Multi-master accepts writes on every peer and propagates them across the cluster. For workloads where multiple nodes can update the same key, design key ownership or application-level write rules so concurrent updates resolve predictably.
You can run multi-master alongside --peers. Choose either follower mode with --replicaof or multi-master mode for a given node.
Each key maps to one of 16,384 slots via CRC32 hashing. Each node owns a contiguous range of slots. When you send a command for a key that lives on a different node, you get back:
MOVED 12182 host2:7380
Your client library follows this redirect to the owner node; most Redis-compatible clients already handle this flow.
A background heartbeat pings every peer every 5 seconds. If a node stops responding, it gets marked as failing and eventually offline. When nodes are added or removed, the slot ranges are recalculated automatically.
For cluster topology changes:
- Pair slot ownership updates with replication, multi-master, or an application-level migration plan so data remains available while ownership changes.
- Use
--replicaoffor follower replication or--multimasterfor peer-to-peer replication, depending on the topology you want. - Use the coordinated/manual failover commands with epoch fencing when promoting a new leader, and validate the topology after promotion.
This keeps routing explicit while giving operators control over replication, promotion, and topology changes.
Here's what a production-ish setup might look like:
vole \
--addr 0.0.0.0:7379 \
--http-addr 0.0.0.0:8080 \
--appendonly \
--appendfilename /var/lib/vole/vole.aof \
--appendfsync everysec \
--snapshot /var/lib/vole/vole.snap \
--snapshot-interval 5m \
--maxmemory 1073741824 \
--maxmemory-policy allkeys-lru \
--requirepass changeme \
--tls-cert /etc/vole/cert.pem \
--tls-key /etc/vole/key.pemThat gives you:
- RESP on port 7379, HTTP on 8080, both encrypted with TLS
- Password required
- AOF persistence with 1-second fsync, plus snapshots every 5 minutes
- 1 GB memory cap with LRU eviction
- Prometheus metrics at
https://host:8080/metrics
| Flag | Default | Description |
|---|---|---|
--addr |
127.0.0.1:7379 |
RESP listen address |
--http-addr |
(off) | HTTP/JSON API listen address |
--appendonly |
true |
Enable append-only file |
--appendfilename |
vole.aof |
AOF path |
--appendfsync |
everysec |
always, everysec, or no |
--snapshot |
vole.rdb.json |
Snapshot path |
--snapshot-interval |
0 |
Auto-snapshot interval (e.g., 5m) |
--maxmemory |
0 |
Memory limit in bytes (0 = unlimited) |
--maxmemory-policy |
noeviction |
Eviction policy |
--requirepass |
(none) | Client password |
--tls-cert |
(none) | TLS certificate path |
--tls-key |
(none) | TLS private key path |
--replicaof |
(none) | Leader address (host:port) |
--multimaster |
false |
Enable multi-master replication |
--node-id |
(auto) | Cluster node ID |
--peers |
(none) | Cluster peer list |