Docs
Home GitHub npm

Storage Backends

Store snapshots locally, on S3, Cloudflare R2, or any S3-compatible service. All backends receive only encrypted data โ€” zero-knowledge by design.

๐Ÿ” Zero-knowledge: Data is encrypted before leaving your machine. Storage backends only ever see encrypted blobs. Even if someone gains access to your bucket, they can't read your data without your passphrase.

Local Storage (Default)

By default, snapshots are stored at ~/.savestate/snapshots/. No configuration needed.

Config

// .savestate/config.json
{
  "storage": {
    "type": "local",
    "options": {
      "path": "~/.savestate"
    }
  }
}

You can change the storage path to any directory:

// Store in Dropbox for automatic sync
{
  "storage": {
    "type": "local",
    "options": {
      "path": "~/Dropbox/savestate-backups"
    }
  }
}
๐Ÿ’ก Set the path to a Dropbox, iCloud Drive, or Google Drive folder for automatic cloud sync while keeping everything encrypted.

Amazon S3

Store snapshots in an S3 bucket. Uses AWS Signature V4 authentication with zero external dependencies โ€” SaveState implements the signing from scratch using native crypto.

Config

// .savestate/config.json
{
  "storage": {
    "type": "s3",
    "options": {
      "bucket": "my-savestate-backups",
      "endpoint": "https://s3.us-east-1.amazonaws.com",
      "region": "us-east-1",
      "accessKeyId": "AKIA...",
      "secretAccessKey": "wJa...",
      "prefix": "snapshots/"
    }
  }
}

Options

OptionRequiredDescription
bucketYesS3 bucket name
endpointYesS3 endpoint URL
regionNoAWS region (default: us-east-1)
accessKeyIdNo*AWS access key ID
secretAccessKeyNo*AWS secret access key
prefixNoKey prefix for all objects (e.g., snapshots/)
timeoutMsNoRequest timeout in ms (default: 30000)
maxRetriesNoMax retries on 5xx errors (default: 3)

* Credentials can also be provided via AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.

Cloudflare R2

Cloudflare R2 is S3-compatible with zero egress fees โ€” a great fit for backups. SaveState has been tested with R2.

Config

// .savestate/config.json
{
  "storage": {
    "type": "r2",
    "options": {
      "bucket": "savestate",
      "endpoint": "https://<account-id>.r2.cloudflarestorage.com",
      "region": "auto",
      "accessKeyId": "<R2 access key ID>",
      "secretAccessKey": "<R2 secret access key>",
      "prefix": "backups/"
    }
  }
}

Setting up R2

  1. Go to your Cloudflare dashboard โ†’ R2 โ†’ Create bucket
  2. Create an API token: R2 โ†’ Manage R2 API Tokens โ†’ Create API Token
  3. Select "Object Read & Write" permissions for your bucket
  4. Copy the Access Key ID, Secret Access Key, and your Account ID
  5. The endpoint is: https://<account-id>.r2.cloudflarestorage.com
๐Ÿ’ก R2 has no egress fees, making it ideal for backups you may need to download frequently. For SaveState, set region to "auto".

Backblaze B2

Backblaze B2 is also S3-compatible. Use the s3 or b2 storage type with your B2 S3-compatible endpoint.

{
  "storage": {
    "type": "b2",
    "options": {
      "bucket": "my-savestate",
      "endpoint": "https://s3.us-west-004.backblazeb2.com",
      "region": "us-west-004",
      "accessKeyId": "<B2 key ID>",
      "secretAccessKey": "<B2 application key>"
    }
  }
}

Sync Folder Storage

For quick cloud backup without setting up S3, just point local storage at a synced folder:

// Dropbox
{ "storage": { "type": "local", "options": { "path": "~/Dropbox/savestate" } } }

// iCloud Drive
{ "storage": { "type": "local", "options": { "path": "~/Library/Mobile Documents/com~apple~CloudDocs/savestate" } } }

// Google Drive
{ "storage": { "type": "local", "options": { "path": "~/Google Drive/savestate" } } }

Implementation Details

All storage backends implement the same interface:

interface StorageBackend {
  readonly id: string;
  put(key: string, data: Buffer): Promise<void>;
  get(key: string): Promise<Buffer>;
  list(prefix?: string): Promise<string[]>;
  delete(key: string): Promise<void>;
  exists(key: string): Promise<boolean>;
}

The S3 backend uses path-style access and implements AWS Signature V4 from scratch with Node.js native crypto โ€” zero external dependencies. It handles retries with exponential backoff on 5xx errors and 429 rate limits.