Storage
The bucket and disks the control plane stores Rivet Actor data on, how to configure them, and what losing one means.
Each Rivet Actor’s data lives in its own durable volume, which holds both its SQLite database and its key-value data. The control plane stores volumes in two places:
| Disk | Bucket | |
|---|---|---|
| What it holds | Recent writes, replicated to the disks of several instances, plus a read cache | The durable copy of every volume |
| When data lands there | Before a write is acknowledged | In the background, shortly after |
| How many | One per control plane instance | One per cluster |
A write is acknowledged once a majority of the instances holding that volume have it on disk, so losing one instance loses no acknowledged write.
Bucket
Set object_storage.primary to one backend. Use S3, an S3-compatible store, Google Cloud Storage or Azure Blob Storage in production. The local file system and in-memory backends are for trying Rivet on one machine.
Amazon S3
{
"object_storage": {
"primary": {
"s3": {
"bucket": "my-rivet-bucket",
"region": "us-east-1",
"access_key_id": "AKIA...",
"secret_access_key": "..."
}
}
}
}
| Field | Required | Purpose |
|---|---|---|
bucket | Yes | The bucket name. |
region | No | The bucket’s region. |
access_key_id, secret_access_key | No | Static credentials. Leave them out to use the environment’s AWS credentials, such as the instance’s IAM role. |
endpoint | No | The URL of an S3-compatible store. See the S3-compatible tab. |
prefix | No | A path in the bucket to store Rivet’s objects under. |
S3-compatible
For MinIO, Cloudflare R2, Hetzner Object Storage and other S3-compatible stores, use the s3 backend and add endpoint:
{
"object_storage": {
"primary": {
"s3": {
"bucket": "rivet",
"endpoint": "https://minio.example.com:9000",
"region": "us-east-1",
"access_key_id": "...",
"secret_access_key": "..."
}
}
}
}
The other fields are the same as for Amazon S3.
Google Cloud Storage
{
"object_storage": {
"primary": {
"gcs": {
"bucket": "my-rivet-bucket",
"service_account_key": "<service account key JSON>"
}
}
}
}
| Field | Required | Purpose |
|---|---|---|
bucket | Yes | The bucket name. |
service_account_key | No | A service account key in JSON. Leave it out to use application default credentials, such as the instance’s service account. |
prefix | No | A path in the bucket to store Rivet’s objects under. |
Azure Blob Storage
{
"object_storage": {
"primary": {
"azure": {
"account": "myaccount",
"container": "rivet",
"access_key": "..."
}
}
}
}
| Field | Required | Purpose |
|---|---|---|
account | Yes | The storage account name. |
container | Yes | The container name. |
access_key | No | The storage account access key. Leave it out to use credentials from the environment or a managed identity. |
prefix | No | A path in the container to store Rivet’s objects under. |
Local file system
{
"object_storage": {
"primary": {
"file_system": { "path": "/var/lib/rivet/objects" }
}
}
}
path is the only field. The control plane creates the directory if it is missing.
Only one control plane process may use the directory at a time. Its conditional writes are atomic only within that process, so never share the directory between instances, even over a shared volume. Use it for single-instance setups such as the quickstart.
In memory
{
"object_storage": {
"primary": "in_memory"
}
}
This is the default when object_storage.primary is not set. Data lives in the control plane process and is lost when it restarts. Use it only to try Rivet locally or in tests, with one instance.
The s3, gcs and azure backends accept prefix to store Rivet’s objects under a path in a shared bucket. Give the control plane its own bucket or prefix, and never point two clusters at the same one.
The in-memory backend loses every Rivet Actor’s data on restart, and the file_system backend keeps it on one machine. Neither belongs in production. See the production checklist.
Environment variables
Every setting above can also be set with environment variables, as described in Configuration. The S3 example as environment variables:
RIVET__OBJECT_STORAGE__PRIMARY__S3__BUCKET=my-rivet-bucket
RIVET__OBJECT_STORAGE__PRIMARY__S3__REGION=us-east-1
RIVET__OBJECT_STORAGE__PRIMARY__S3__ACCESS_KEY_ID=AKIA...
RIVET__OBJECT_STORAGE__PRIMARY__S3__SECRET_ACCESS_KEY=...
RIVET__OBJECT_STORAGE__PRIMARY__S3__ENDPOINT=https://minio.example.com:9000
RIVET__OBJECT_STORAGE__PRIMARY__S3__PREFIX=rivet
Set only the fields you need. The same pattern works for the other backends, for example RIVET__OBJECT_STORAGE__PRIMARY__GCS__BUCKET and RIVET__OBJECT_STORAGE__PRIMARY__AZURE__CONTAINER.
Disks
Set depot.log_directory to a directory on the instance’s disk. The directory must already exist.
- One disk per instance. The disk holds the instance’s identity. Never share it, copy it to another instance, or mount it on two instances.
- Block storage only. Use local SSDs or block volumes such as EBS or Persistent Disk. Network file systems such as NFS and EFS are not supported.
- Size. The control plane sizes its use of the disk from the free space at startup and keeps at least 10% free. Give each instance at least 100 GiB in production.
The read cache lives in the same directory by default. Move it to another disk with depot.cold_store.disk_cache_directory; it is disposable.
Losing a disk or an instance
| What is lost | What happens |
|---|---|
| One instance of three or more | Nothing is lost. After about two minutes the control plane rebuilds its replicas on the remaining instances. |
| A single-instance setup’s disk | Writes that had not reached the bucket yet are lost. |
| The bucket | Every volume’s durable copy is lost. See Backup & restore. |