Skip to content

S3-compatible storage

forze[s3] implements object storage — upload, download, list, delete — on AWS S3 or any S3-compatible endpoint (MinIO, Yandex, …), behind the storage contracts.

Install

uv add 'forze[s3]'

Needs an S3-compatible store. Forze uses existing buckets; it doesn't create them.

The client

from forze_s3 import S3Client

s3 = S3Client()

RoutedS3Client (with S3RoutingCredentials) resolves per-tenant endpoints and keys.

Settings

S3Settings holds the endpoint, region and static credentials, refusing a half-set pair (an incomplete pair cannot sign, and refusing it here names the missing variable) — see connection settings.

Wire it

Each storage route names a bucket and is keyed by StorageSpec.name:

from forze.application.execution import DepsRegistry, LifecyclePlan
from forze_s3 import (
    S3Client,
    S3DepsModule,
    S3StorageConfig,
    s3_bucket_lifecycle_step,
    s3_lifecycle_step,
)

deps = DepsRegistry.from_modules(
    S3DepsModule(client=s3, storages={"assets": S3StorageConfig(bucket="my-assets")}),
)
lifecycle = LifecyclePlan.from_steps(
    s3_lifecycle_step(endpoint="https://s3.amazonaws.com", access_key_id="…", secret_access_key="…"),
    s3_bucket_lifecycle_step(buckets=["my-assets"]),  # optional: create missing buckets at startup
)

s3_bucket_lifecycle_step runs after the client starts and leaves an existing bucket alone; a bucket it cannot create fails startup. It writes shared infrastructure, so under a FLEET profile wrap it in a singleton lifecycle step.

What it provides

Contract Operations Keyed by
Storage query download, download_stream, download_range, download_if_changed, head, presign_download, list StorageSpec.name (storages)
Storage command upload, upload_stream, overwrite_stream, presign_upload, delete, copy, move, put_object_tags StorageSpec.name (storages)
Upload sessions (resumable multipart) begin … complete / abort StorageSpec.name (storages)

The full method surface is the storage contract; the streamed and ranged downloads are what the generated download route serves by default.

Notes

  • A bucket is required per route — S3StorageConfig(bucket=...); an empty static bucket name is a configuration error.
  • Forze never deletes buckets. It creates a missing one on first write, or at startup with s3_bucket_lifecycle_step after s3_lifecycle_step. The step needs a plain S3Client: a tenant-routed client has no tenant at startup, so its buckets are created on first write.
  • The bucket can be a static name or a per-tenant resolver; RoutedS3Client + S3RoutingCredentials cover per-tenant endpoints/credentials.
  • Downloads return raw bytes — register the FastAPI exception handlers so a missing object maps to a 404.