Building blocks

Scoped file storage

Documentation version: 858adedd187db2e94614b1dfd389e4bf98e6e202:ac5d527caaa1f97eee9d71262e7c843ae7b24000e01ba5b44931108b2b489c0d

Status: the controlled Shared step 6 profile is validated in this private source checkpoint. See the module record and validation ledger. Single-node Garage tests do not establish storage host redundancy.

Ownership and compatibility

Garage 2.5.0 supplies native S3 object storage. The internal minio-go client is pinned in modules/storage/go.mod. Go metadata owns environment namespaces, subject grants, atomic byte reservations, file references and lifecycle state. The shared operation coordinator creates namespaces. Applications receive scoped file operations, never account-wide S3 commands or credentials.

The native engine and internal client remain ordinary maintained dependencies. Their licenses/notices and protocol names retain upstream ownership. The supported public interface is the generated API and SDK below, not every operation exposed by S3 or InstantDB's retained native storage source.

SDK lifecycle

createStorageClient is exported by @astrogate/sdk/browser and @astrogate/sdk/server. Supply a validated ServiceBinding, explicit deadlineMs/maxAttempts, and, on a server, the request's sessionToken. Browser calls use the configured authority session. Relevant signatures are compiled in sdk/test/services.types.ts and exercised in the synthetic Next.js/Vite fixtures.

  1. reserve({sizeBytes, sha256, filename, contentType}, {idempotencyKey, signal?}) reserves the complete declared byte count atomically.
  2. upload({objectId, body}, {signal?}) sends bytes for that existing reservation. Verify the SHA-256 of the actual content before reserving.
  3. metadata(objectId, {signal?}) returns authorized metadata. download(objectId, {signal?}) returns the content response.
  4. references.attach({objectId, referenceId}, {signal?}) protects content needed by a database record or job. references.detach releases that protection through the same authorization owner.
  5. delete(objectId, {signal?}) is subject to references and retention. It cannot bypass those requirements merely to free quota.

Mutations and retries retain the same logical reservation/key. A lost native reply leaves an uncertain effect charged until reconciliation verifies it. Pending/deleting objects cannot be reported as a completed recovery point. Quota exhaustion is actionable; it must not delete files still needed for execution or recovery. Transport retries do not replace caller business-effect idempotency.

Placement, recovery and development

File engines and byte quotas come from an installation-owned profile. Names derive from resource/object identities, not arbitrary supplied bucket paths. Every request rechecks scope, grant/revocation and placement barriers. A jobs session cannot authorize file operations.

Moves fence writes first, copy acknowledged objects to the declared target engine, read and hash actual destination bytes, and commit metadata/bindings only after verification. A native object hash header alone is insufficient. Return moves must include newly acknowledged destination writes.

A coordinated backup contains native payloads, object inventory/checksums, file ownership/reference metadata and the corresponding application-data boundary. PostgreSQL metadata or an S3 directory alone is insufficient. Whole-installation operator backups are distinct from scoped customer exports. Unknown/missing referenced payloads block recovery instead of being silently omitted.

Hosted and local Preview use the same scoped bindings and SDK. SDK imports do not allocate namespaces. Explicit bootstrap starts/reuses the configured dependency profile; stop/restart must preserve stored objects and mutable workspace source. See development workspaces and building-block contracts.

On this page