Beignet API reference
    Preparing search index...

    Module @beignet/provider-storage-s3

    @beignet/provider-storage-s3

    S3-compatible object storage provider for Beignet.

    The provider installs the app-facing ctx.ports.storage port. Use it for production object storage on AWS S3, Cloudflare R2, MinIO, Backblaze B2, DigitalOcean Spaces, or another S3-compatible backend.

    bun add @beignet/provider-storage-s3
    
    import { s3StorageProvider } from "@beignet/provider-storage-s3";
    import { createServer } from "@beignet/core/server";

    const server = await createServer({
    ports: basePorts,
    providers: [s3StorageProvider],
    createContext: ({ ports }) => ({ ports }),
    routes,
    });

    Environment variables:

    Variable Description
    STORAGE_S3_BUCKET Bucket name.
    STORAGE_S3_REGION Region. Defaults to us-east-1. Use auto for Cloudflare R2.
    STORAGE_S3_ENDPOINT Optional S3-compatible endpoint. Required for R2, MinIO, Spaces, B2, and similar services.
    STORAGE_S3_ACCESS_KEY_ID Optional static access key.
    STORAGE_S3_SECRET_ACCESS_KEY Optional static secret key.
    STORAGE_S3_SESSION_TOKEN Optional static session token.
    STORAGE_S3_PUBLIC_BASE_URL Optional base URL returned by publicUrl(...) for public objects.
    STORAGE_S3_FORCE_PATH_STYLE Optional true or false path-style addressing toggle.
    STORAGE_S3_KEY_PREFIX Optional prefix for every object key written by this app.
    STORAGE_S3_BUCKET=my-app-assets
    STORAGE_S3_REGION=us-east-1
    STORAGE_S3_PUBLIC_BASE_URL=https://cdn.example.com

    When credentials are omitted, the AWS SDK uses its normal credential provider chain.

    STORAGE_S3_BUCKET=my-app-assets
    STORAGE_S3_REGION=auto
    STORAGE_S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
    STORAGE_S3_ACCESS_KEY_ID=...
    STORAGE_S3_SECRET_ACCESS_KEY=...
    STORAGE_S3_PUBLIC_BASE_URL=https://assets.example.com

    R2 is S3-compatible, but not every S3 feature exists on every compatible service. This provider only relies on object put, get, head, and delete.

    import { createS3Storage } from "@beignet/provider-storage-s3";

    const storage = createS3Storage({
    bucket: "my-app-assets",
    region: "auto",
    endpoint: "https://<account-id>.r2.cloudflarestorage.com",
    credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY_ID!,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
    },
    publicBaseUrl: "https://assets.example.com",
    });

    The same StoragePort works with local files, memory tests, and S3-compatible object stores:

    await ctx.ports.storage.put("avatars/user_123.png", avatarBytes, {
    contentType: "image/png",
    visibility: "public",
    });

    const object = await ctx.ports.storage.get("avatars/user_123.png");
    const url = await ctx.ports.storage.publicUrl("avatars/user_123.png");

    Use createS3UploadSigner(...) with @beignet/core/uploads when browsers should upload directly to S3 or an S3-compatible service:

    import { createUploadRouter } from "@beignet/core/uploads";
    import { createS3UploadSigner } from "@beignet/provider-storage-s3";

    const uploadRouter = createUploadRouter({
    uploads: postUploads,
    ctx: () => server.createContextFromNext(),
    storage: server.ports.storage,
    signer: createS3UploadSigner({
    bucket: "my-app-assets",
    region: "auto",
    endpoint: "https://<account-id>.r2.cloudflarestorage.com",
    credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY_ID!,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
    },
    keyPrefix: "production",
    }),
    });

    The signer returns presigned PUT URLs with the content type, cache control, and Beignet storage metadata headers the browser must send.

    visibility is stored as reserved object metadata so publicUrl(...) can return URLs only for objects written with visibility: "public". The provider does not set S3 ACLs. Configure bucket policies, R2 public buckets, or a CDN outside the provider when objects should be publicly reachable.

    The reserved metadata key is beignet-visibility. It is hidden from StorageObject.metadata.

    The provider also installs ctx.ports.s3Storage for S3-specific operations that do not belong in StoragePort:

    import { ListObjectsV2Command } from "@aws-sdk/client-s3";

    const s3Key = ctx.ports.s3Storage.objectKey("exports/report.csv");
    const s3Prefix = ctx.ports.s3Storage.objectPrefix("exports");

    await ctx.ports.s3Storage.client.send(
    new ListObjectsV2Command({
    Bucket: ctx.ports.s3Storage.bucket,
    Prefix: s3Prefix,
    }),
    );

    Use objectKey(...) when direct S3 calls need to address objects written through ctx.ports.storage. Use objectPrefix(...) for list operations. Both helpers apply the configured STORAGE_S3_KEY_PREFIX.

    When ctx.ports.devtools is installed, the provider records storage operations under the storage watcher and direct upload signing under the uploads watcher. Events include operation name, key, bucket, duration, object size, visibility, and whether a lookup hit. Object bodies and metadata values are never recorded.

    MIT

    Interfaces

    S3StorageOptions
    S3StorageProviderOptions
    S3StorageProviderPorts
    S3UploadSignerOptions
    StorageObject
    StorageObjectBody
    StoragePort

    Type Aliases

    S3StorageClient
    S3StorageConfig
    StorageBody
    StorageMetadata
    StorageVisibility

    Variables

    s3StorageProvider

    Functions

    createS3Storage
    createS3StorageProvider
    createS3UploadSigner