Backends
S3 & compatible
A filesystem over any S3-compatible object store — AWS, R2, MinIO, GCS interop, and more.
A vfs.FileSystem over any S3-compatible object store (AWS S3, Cloudflare R2,
GCS interop, OCI, Supabase, MinIO). Configure non-AWS stores with an endpoint
and path_style: true.
Configuration
remotes:
aws:
type: s3
region: us-east-1
credentials:
access_key_id: env:AWS_ACCESS_KEY_ID
secret_access_key: keychain:dumont/aws
r2:
type: s3
endpoint: https://<acct>.r2.cloudflarestorage.com
region: auto
path_style: true # required for most non-AWS stores
credentials:
access_key_id: env:R2_ACCESS_KEY_ID
secret_access_key: env:R2_SECRET_ACCESS_KEYAddress it as <remote>://<bucket>/<key>. A bucket is required.
Capabilities
| Cap | Value | Why |
|---|---|---|
| RandomRead | ✅ | ranged GetObject (Range header) |
| RandomWrite | ❌ | object stores only replace whole objects; OpenFile(O_RDWR) → ErrNotSupported |
| Append | ❌ | O_APPEND → ErrNotSupported |
| Truncate | ❌ | no in-place resize |
| AtomicRename | ❌ | rename = server-side copy + delete (non-atomic window) |
| Directories | ❌ | synthesized from key prefixes |
| MTime | ✅ | LastModified (second resolution) |
| CaseSensitive | ✅ | object keys are case-sensitive |
Add emulate: true to layer read-modify-write random write/append on top (see
Architecture).
Semantic surprises
- Directories are synthetic. A "directory" is just a common key prefix.
ReadDirderives entries from delimiter-basedListObjectsV2(CommonPrefixes→ subdirs,Contents→ files).Mkdirwrites a zero-bytepath/marker so empty directories can exist; markers are hidden fromReadDir. - Writes are whole-object. Sequential writes are buffered and committed on
Close— a singlePutObject, or a multipart upload above 8 MiB (5 MiB parts). There is no partial/streaming commit;Syncis a no-op. - Rename copies.
RenameisCopyObject+DeleteObject. Renaming a "directory" copies and deletes every key under the prefix (paginated). Not atomic — a crash mid-rename can leave both or neither. - mtime is second-resolution. S3 exposes
Last-Modifiedover HTTP at one-second granularity, while list XML carries sub-second values. The backend truncates to whole seconds soStatandReadDiragree. list-after-write can lag. Object reads are read-after-write consistent, but listings may briefly omit a just-written key on some stores. dumont prefers authoritative reads after writes it performed.
Testing
Conformance runs in-process against gofakes3 (no Docker), including a
8 MiB multipart round-trip.