Pre-release. bakelite is unreleased and still under active testing — docs and behaviour may change without notice.

Backends

bakelite writes replicas to a pluggable storage backend. Five families exist today:

GCS and Azure go through the identical ObjectStoreBackend mapping that the S3 backend uses, so they go through the same Backend-trait conformance tests the in-memory and S3 suites run. The S3-specific version-overhead inspection (bakelite usage noncurrent-version reporting) and multipart reclaim are S3-only — on GCS/Azure, as on R2, bakelite usage reports that overhead as "not inspected". A dedicated live-target CI leg (gcs-azure-providers.yml) now runs the native GCS and Azure backends against real accounts, mirroring s3-providers.yml.

Why a compatibility matrix

"S3-compatible" is a spectrum. Services agree on the core object API but diverge at the edges — versioning semantics, multipart-upload listing, lifecycle behavior. We learned this the hard way: MinIO's ListMultipartUploads silently ignores the prefix parameter (real AWS honours it), which would have made multipart reclaim miss orphans on MinIO had we relied on server-side filtering. Emulators don't always match real-service behavior (the MinIO prefix handling above is one example), so bakelite is tested against the real services too, not just emulators.

How it's tested

One parameterized conformance suite (s3_conformance in crates/bakelite-core/tests/backend_conformance.rs) runs against every target by reading BAKELITE_TEST_S3_* env. It exercises four layers:

  1. the full Backend trait contract (incl. the streaming snapshot/multipart path);
  2. S3 inspection — versioning + version-overhead reporting;
  3. reclaim end-to-end — create a dangling multipart upload, list it, age-gate it, abort it, and check it's removed (the regression guard for the prefix divergence);
  4. a capability probe that records raw provider behavior (it never asserts) and emits BAKELITE_CAPABILITY_JSON {…}, the source for the table below.

Compatibility matrix

ProviderTrait conformanceVersioning inspectionMultipartListMultipartUploads prefix honouredNoncurrent versionsDelete markers
Local filesystem
SFTP✅⁴
AWS S3✅ enabled
Cloudflare R2❌ (403)¹—¹—¹
Backblaze B2✅ enabled
MinIO✅ enabled❌²
LocalStack (3.x)✅ (off by default)
Google Cloud Storage✅³—³—³—³
Azure Blob✅³—³—³—³

Measured by the suite's capability probe — emulator rows in PR CI, real-provider rows from s3-providers.yml; the GCS/Azure trait-conformance column comes from gcs-azure-providers.yml.

Notes:

  1. Cloudflare R2 answers GetBucketVersioning / ListObjectVersions with 403 — it doesn't expose the object-versioning APIs. bakelite tolerates this: bakelite usage reports version overhead as "not inspected" on R2, and replication, restore, and multipart reclaim all work normally (R2 does support multipart, and honours the prefix). It only means R2's hidden-version overhead can't be reported.
  2. MinIO silently ignores the prefix on ListMultipartUploads and returns every upload. bakelite never relies on server-side prefix filtering (it lists whole-bucket and filters client-side), so reclaim is correct here regardless — this column documents the divergence that drove that design. Every other tested service honours the prefix.
  3. Google Cloud Storage / Azure Blob use the same object_store-backed ObjectStoreBackend as S3. Their trait conformance (✅³) is now exercised against a live account by the dedicated gcs-azure-providers.yml CI leg (gcs_conformance / azure_conformance), on top of the shared in-memory and S3 suites. The S3-only version-overhead inspection and multipart reclaim don't apply (—³); large snapshots still stream as multipart via object_store (GCS resumable uploads / Azure block blobs). Expire old data with the provider's own lifecycle/object-versioning controls. See the per-provider setup notes under Configuration → Google Cloud Storage and Azure Blob Storage.
  4. SFTP runs the same Backend-trait conformance suite the other backends do, against a disposable atmoz/sftp server — locally via just sftp-up && just test-sftp. Being a plain remote filesystem, the S3-only columns (versioning, multipart) don't apply.

Noncurrent versions / delete markers are only observable on a bucket with versioning enabled, and bakelite never deletes object versions — object versions are a separate disaster-recovery layer that bakelite leaves alone; expire noncurrent versions with a bucket lifecycle policy. See S3 storage overhead.