Skip to content
Files SDK
Esc
navigateopen⌘Jpreview
On this page

Bun S3

AWS S3 (and any S3-compatible bucket) via Bun's native Bun.S3Client instead of @aws-sdk/client-s3. Bun-only.

Installation

This adapter has no extra peer dependencies, but it requires the Bun runtime - it’s built on Bun’s native Bun.S3Client, which Node doesn’t provide. (Outside Bun it throws unless you hand it a Bun.S3Client-shaped client yourself.)

npm install files-sdk
pnpm add files-sdk
yarn add files-sdk
bun add files-sdk

Usage

import { Files } from "files-sdk";
import { bunS3 } from "files-sdk/bun-s3";

const files = new Files({
  adapter: bunS3({
    bucket: "uploads",
    region: "us-east-1",
    // accessKeyId / secretAccessKey auto-loaded by Bun from
    // S3_ACCESS_KEY_ID / S3_SECRET_ACCESS_KEY (or AWS_* equivalents)
  }),
});

// Or hand it the singleton Bun.s3 client directly:
new Files({ adapter: bunS3({ client: Bun.s3 }) });

Three things differ from files-sdk/s3: copy() streams bytes through your process because Bun doesn’t expose a server-side CopyObject primitive; upload() throws on metadata and cacheControl because Bun.S3Client.write() has no equivalent options; and signedUploadUrl() throws on maxSize because Bun exposes presigned URLs only - not S3 POST policy fields. Reach for files-sdk/s3 on the same bucket when you need any of those.

Options

PropType
client?BunS3ClientLike

A pre-configured `Bun.S3Client`-shaped instance — for example the global `Bun.s3`, or one constructed with specific credentials elsewhere in your app. When set, the adapter uses it as-is and rejects any of `bucket`, `region`, `endpoint`, `virtualHostedStyle`, `accessKeyId`, `secretAccessKey`, `sessionToken` at construction (they would be silently ignored otherwise). When unset, the adapter constructs its own client from the options below.

TypeBunS3ClientLike
bucket?string

S3 bucket name. Scopes operations and is exposed as `adapter.bucket`. Falls back to `S3_BUCKET` / `AWS_BUCKET` via Bun's built-in resolution.

Typestring
region?string

AWS region (e.g. `us-east-1`). Falls back to `S3_REGION` / `AWS_REGION` via Bun's resolution.

Typestring
endpoint?string

Override the S3 service endpoint. Use this to point at S3-compatible services (R2, DigitalOcean Spaces, Wasabi, MinIO, ...).

Typestring
virtualHostedStyle?boolean

Use virtual-hosted-style addressing (`https://<bucket>.<endpoint>`) instead of path-style. Defaults to `false` — flip on for endpoints that require it.

Typeboolean
accessKeyId?string

Static access key ID. Skip to let Bun resolve it from `S3_ACCESS_KEY_ID` / `AWS_ACCESS_KEY_ID`.

Typestring
secretAccessKey?string

Static secret access key. Skip to let Bun resolve it from `S3_SECRET_ACCESS_KEY` / `AWS_SECRET_ACCESS_KEY`.

Typestring
sessionToken?string

Static session token for temporary credentials. Skip to let Bun resolve it from `S3_SESSION_TOKEN` / `AWS_SESSION_TOKEN`.

Typestring
publicBaseUrl?string

Origin used to build URLs from `url()`. When set, `url(key)` returns `${publicBaseUrl}/${key}` and skips signing — use this if your bucket is fronted by a CDN or has a public-read policy. Passing `responseContentDisposition` still forces a signed URL even when this is set, because a permanent CDN URL has no signature in which to bind the override. When unset, `url()` returns a presigned GetObject (1-hour default).

Typestring
defaultUrlExpiresIn?number

Default expiry, in seconds, for the presigned URLs returned by `url()` when `publicBaseUrl` isn't set. Defaults to 3600 (1 hour). Per-call `url(key, { expiresIn })` overrides.

Typenumber

Compatibility

Method Status Notes
upload ⚠️ User metadata and cacheControl throw - Bun.S3Client.write() exposes neither field. Reach for s3() on the same bucket if you need them. Stream bodies are wrapped in a Response and handed to Bun’s writer. Pause/resume via control is in-process only — Bun’s S3 client exposes no resumable upload id, so chunks are buffered and a token cannot resume in a new process.
download
delete
list
search
head
exists
copy ⚠️ Client-side stream copy - Bun.S3Client doesn’t expose a server-side CopyObject, so the source is streamed through this process and re-uploaded. Doubled bandwidth, not atomic, and drops Content-Disposition/cache headers/user metadata/ACL (only Content-Type is preserved). Reach for s3() on the same bucket for server-side copy.
url
signedUploadUrl ⚠️ PUT URL only - Bun exposes presigned URLs, not S3 POST policy fields, so maxSize throws (no content-length-range policy). Enforce upload caps at your application gateway instead.

Was this page helpful?