S3-durable key-value storage with etcd v3 compatibility
See the codeT4 is an open-source key-value database built on object storage.
It is designed for durable infrastructure state: config, coordination, watches, leases, transactions, recovery, and branching. T4 stores data locally for fast access, persists WAL segments and checkpoints to S3-compatible object storage, and can speak the etcd v3 API for existing infrastructure clients.
Infrastructure systems often need a small, reliable place to keep control-plane state: configuration, service metadata, locks, leases, and change notifications.
etcd is the standard answer, but operating a consensus cluster is not always the shape you want. For small platforms, edge deployments, development environments, ephemeral nodes, and systems that already trust object storage, a full Raft membership model can be more machinery than the state store deserves.
T4 explores a different tradeoff: keep the familiar key-value and watch primitives, store hot data locally, and use object storage as the durable recovery layer. Nodes can disappear, lose their disks, or be replaced; the database can rebuild from WAL segments and checkpoints in S3-compatible storage.
t4 as a server, or call t4.Open(cfg) inside a Go process. No sidecar required.T4_* environment variables.import "github.com/t4db/t4"
node, err := t4.Open(t4.Config{
DataDir: "/var/lib/myapp/t4",
})
defer node.Close()
rev, err := node.Put(ctx, "/config/timeout", []byte("30s"), 0)
kv, err := node.Get("/config/timeout")
fmt.Println(string(kv.Value)) // 30s
events, _ := node.Watch(ctx, "/config/", 0)
for e := range events {
fmt.Printf("%s %s=%s\n", e.Type, e.KV.Key, e.KV.Value)
}
import (
"github.com/t4db/t4"
"github.com/t4db/t4/pkg/object"
)
store, err := object.NewS3StoreFromConfig(ctx, object.S3Config{
Bucket: "my-bucket",
Prefix: "t4/",
Region: "us-east-1",
// Endpoint: "http://localhost:9000", // any S3-compatible store
})
if err != nil {
return err
}
node, err := t4.Open(t4.Config{
DataDir: "/var/lib/myapp/t4",
ObjectStore: store,
})
The t4 binary exposes the etcd v3 gRPC protocol. Use etcdctl, the official Go client, or any other etcd v3 compatible tool.
go install github.com/t4db/t4/cmd/t4@latest
# Single node, local only
t4 run --data-dir /var/lib/t4 --listen 0.0.0.0:3379
# Single node with S3
t4 run --data-dir /var/lib/t4 --listen 0.0.0.0:3379 \
--s3-bucket my-bucket --s3-prefix t4/
# The same configuration can come from environment variables.
T4_DATA_DIR=/var/lib/t4 \
T4_LISTEN=0.0.0.0:3379 \
T4_S3_BUCKET=my-bucket \
T4_S3_PREFIX=t4/ \
T4_S3_REGION=us-east-1 \
t4 run
# Verify
etcdctl --endpoints=localhost:3379 put /hello world
etcdctl --endpoints=localhost:3379 get /hello
For offline inspection of a local data directory, use t4 inspect:
# Show local metadata without starting a server.
t4 inspect meta --data-dir /var/lib/t4
# Explore current keys.
t4 inspect list --data-dir /var/lib/t4 --prefix /config/
t4 inspect get --data-dir /var/lib/t4 /config/timeout
# Explore revision history and changes over time.
t4 inspect history --data-dir /var/lib/t4 /config/timeout
t4 inspect diff --data-dir /var/lib/t4 --from-rev 100 --to-rev 120 --prefix /config/
Multi-node and production setup: see Operations.
Branches fork a database from an existing S3 checkpoint without copying shared SST files.
# Register the branch against the source prefix.
checkpoint_key=$(t4 branch fork \
--s3-bucket my-bucket \
--s3-prefix t4/ \
--branch-id experiment)
# Start the branch in its own prefix, using the source prefix as its ancestor.
t4 run \
--data-dir /var/lib/t4-experiment \
--listen 0.0.0.0:3379 \
--s3-bucket my-bucket \
--s3-prefix t4-experiment/ \
--branch-prefix t4/ \
--branch-checkpoint "$checkpoint_key"
When the branch is retired, remove its registry entry so future GC can reclaim unneeded source objects:
t4 branch unfork --s3-bucket my-bucket --s3-prefix t4/ --branch-id experiment
Full documentation is available at t4db.github.io/t4.
| Document | Contents |
|---|---|
| Getting Started | Quickstart for standalone server and embedded Go library |
| API Reference | Full Go API — methods, types, errors, branching |
| Configuration | All config fields and CLI flags |
| v1 Compatibility Contract | Stable API, config, object-store, WAL, and checkpoint format contracts |
| Operations | Multi-node clusters, S3, TLS, authentication, RBAC, observability |
| Backup and Restore | Checkpoints, point-in-time restore, branching, retention |
| Security | TLS, mTLS, client auth, RBAC setup |
| Recipes | Distributed locks, service discovery, common patterns |
| Kubernetes | Helm chart, StatefulSet deployment |
| Docker Compose | Local, S3-backed, and multi-node cluster examples |
| Architecture | Internals — WAL, checkpoints, leader election, replication |
| Benchmarks | T4 vs etcd benchmark results and analysis |
| Migrating from etcd | Compatibility table and migration steps |
| Troubleshooting | Diagnostics, debug logging, and common fixes |
| FAQ | Frequently asked questions |
1,833 followers · starred Aug 2026
642 followers · starred Apr 2026
740 followers · starred Jul 2026
830 followers · starred Apr 2026
Go
93.1%
Clojure
1.8%
JavaScript
1.5%
Astro
1.3%
S3-durable key-value storage with etcd v3 compatibility
See the codeT4 is an open-source key-value database built on object storage.
It is designed for durable infrastructure state: config, coordination, watches, leases, transactions, recovery, and branching. T4 stores data locally for fast access, persists WAL segments and checkpoints to S3-compatible object storage, and can speak the etcd v3 API for existing infrastructure clients.
Infrastructure systems often need a small, reliable place to keep control-plane state: configuration, service metadata, locks, leases, and change notifications.
etcd is the standard answer, but operating a consensus cluster is not always the shape you want. For small platforms, edge deployments, development environments, ephemeral nodes, and systems that already trust object storage, a full Raft membership model can be more machinery than the state store deserves.
T4 explores a different tradeoff: keep the familiar key-value and watch primitives, store hot data locally, and use object storage as the durable recovery layer. Nodes can disappear, lose their disks, or be replaced; the database can rebuild from WAL segments and checkpoints in S3-compatible storage.
t4 as a server, or call t4.Open(cfg) inside a Go process. No sidecar required.T4_* environment variables.import "github.com/t4db/t4"
node, err := t4.Open(t4.Config{
DataDir: "/var/lib/myapp/t4",
})
defer node.Close()
rev, err := node.Put(ctx, "/config/timeout", []byte("30s"), 0)
kv, err := node.Get("/config/timeout")
fmt.Println(string(kv.Value)) // 30s
events, _ := node.Watch(ctx, "/config/", 0)
for e := range events {
fmt.Printf("%s %s=%s\n", e.Type, e.KV.Key, e.KV.Value)
}
import (
"github.com/t4db/t4"
"github.com/t4db/t4/pkg/object"
)
store, err := object.NewS3StoreFromConfig(ctx, object.S3Config{
Bucket: "my-bucket",
Prefix: "t4/",
Region: "us-east-1",
// Endpoint: "http://localhost:9000", // any S3-compatible store
})
if err != nil {
return err
}
node, err := t4.Open(t4.Config{
DataDir: "/var/lib/myapp/t4",
ObjectStore: store,
})
The t4 binary exposes the etcd v3 gRPC protocol. Use etcdctl, the official Go client, or any other etcd v3 compatible tool.
go install github.com/t4db/t4/cmd/t4@latest
# Single node, local only
t4 run --data-dir /var/lib/t4 --listen 0.0.0.0:3379
# Single node with S3
t4 run --data-dir /var/lib/t4 --listen 0.0.0.0:3379 \
--s3-bucket my-bucket --s3-prefix t4/
# The same configuration can come from environment variables.
T4_DATA_DIR=/var/lib/t4 \
T4_LISTEN=0.0.0.0:3379 \
T4_S3_BUCKET=my-bucket \
T4_S3_PREFIX=t4/ \
T4_S3_REGION=us-east-1 \
t4 run
# Verify
etcdctl --endpoints=localhost:3379 put /hello world
etcdctl --endpoints=localhost:3379 get /hello
For offline inspection of a local data directory, use t4 inspect:
# Show local metadata without starting a server.
t4 inspect meta --data-dir /var/lib/t4
# Explore current keys.
t4 inspect list --data-dir /var/lib/t4 --prefix /config/
t4 inspect get --data-dir /var/lib/t4 /config/timeout
# Explore revision history and changes over time.
t4 inspect history --data-dir /var/lib/t4 /config/timeout
t4 inspect diff --data-dir /var/lib/t4 --from-rev 100 --to-rev 120 --prefix /config/
Multi-node and production setup: see Operations.
Branches fork a database from an existing S3 checkpoint without copying shared SST files.
# Register the branch against the source prefix.
checkpoint_key=$(t4 branch fork \
--s3-bucket my-bucket \
--s3-prefix t4/ \
--branch-id experiment)
# Start the branch in its own prefix, using the source prefix as its ancestor.
t4 run \
--data-dir /var/lib/t4-experiment \
--listen 0.0.0.0:3379 \
--s3-bucket my-bucket \
--s3-prefix t4-experiment/ \
--branch-prefix t4/ \
--branch-checkpoint "$checkpoint_key"
When the branch is retired, remove its registry entry so future GC can reclaim unneeded source objects:
t4 branch unfork --s3-bucket my-bucket --s3-prefix t4/ --branch-id experiment
Full documentation is available at t4db.github.io/t4.
| Document | Contents |
|---|---|
| Getting Started | Quickstart for standalone server and embedded Go library |
| API Reference | Full Go API — methods, types, errors, branching |
| Configuration | All config fields and CLI flags |
| v1 Compatibility Contract | Stable API, config, object-store, WAL, and checkpoint format contracts |
| Operations | Multi-node clusters, S3, TLS, authentication, RBAC, observability |
| Backup and Restore | Checkpoints, point-in-time restore, branching, retention |
| Security | TLS, mTLS, client auth, RBAC setup |
| Recipes | Distributed locks, service discovery, common patterns |
| Kubernetes | Helm chart, StatefulSet deployment |
| Docker Compose | Local, S3-backed, and multi-node cluster examples |
| Architecture | Internals — WAL, checkpoints, leader election, replication |
| Benchmarks | T4 vs etcd benchmark results and analysis |
| Migrating from etcd | Compatibility table and migration steps |
| Troubleshooting | Diagnostics, debug logging, and common fixes |
| FAQ | Frequently asked questions |
1,833 followers · starred Aug 2026
642 followers · starred Apr 2026
740 followers · starred Jul 2026
830 followers · starred Apr 2026
Go
93.1%
Clojure
1.8%
JavaScript
1.5%
Astro
1.3%