A configuration server for shared settings
One JSON document.
Every service reads it.
Clients read and write paths such as product.name over HTTP or a line-based TCP protocol. Writes go to an append-only file, and several nodes can run as a Raft cluster.
$ docker run -p 23456:23456 shonhen/simpleconf
- 1.02M
- HTTP GET/s at 200 connections
- 16.5M
- TCP GET/s, 64 commands pipelined
- 10 ns
- keyed read, whatever the document size
- 3
- fsync modes, from always to no
Features
For settings that are read often
and changed occasionally.
Feature flags, endpoints, limits. One binary, MIT licensed.
-
Key paths
Read and write paths such as
friends.0.last. Over TCP, reads also take gjson queries such asfriends.#(age>45)#.first. -
HTTP and TCP
A plain HTTP API, and a line-based TCP protocol that answers pipelined commands in fewer writes.
-
Append-only file
A background writer batches records. You choose when it fsyncs:
always,everysecorno. -
Raft cluster
Writes are committed through the leader. Followers pass writes on to it over the Raft port.
-
Peers mode
A simpler option kept for existing deployments: each node queues its writes and sends them to the others.
-
Fails loudly
When the disk breaks, writes are refused or the server exits, as Redis and PostgreSQL do.
Performance
1.02M GET/s over HTTP.
16.5M over pipelined TCP.
Requests per second for one key, wrk -t4 -c200, every server on the same machine. Higher is better.
| Operation | Server | Requests per second |
|---|---|---|
| GET | simpleconf | 1.02M |
| Consul 1.21 | 162k | |
| etcd 3.6 | 44k | |
| PUT | simpleconf | 674k |
| Consul 1.21 | 46k | |
| etcd 3.6 | 33k |
simpleconf fsyncs once a second by default; etcd and Consul fsync every write before replying, so these gaps overstate the difference in code. Setup, Valkey results and caveats: docs/benchmarks.md.
Durability
You choose when it fsyncs.
db.fsync | Survives kill -9 | Survives power loss | Cost |
|---|---|---|---|
always | writes wait for the fsync | ||
everysec (default) | up to 1s of writes lost | negligible | |
no | lost until the OS flushes | none |
With Raft, raft.fsync decides instead: by default a write is acknowledged once a majority of nodes have fsynced it.
Get started
Up in one command.
$ docker run -p 23456:23456 -v simpleconf-data:/data shonhen/simpleconf
$ go install github.com/shaunlee/simpleconf/cmd/simpleconf@latest
$ DB_DIR=./data simpleconf
Data lives in the /data volume. linux/amd64 and linux/arm64.
Go 1.25 or later. HTTP listens on :23456.
When something else fits better
Use etcd or Consul if you need:
- Watches on keys
- Per-key access control or TLS
- Data that does not comfortably fit in memory