Bun.S3Client constructor options
The S3Client constructor accepts the following options: accessKeyId (string), secretAccessKey (string), bucket (string), sessionToken (optional string), acl (optional string), endpoint (optional string), region (optional string), and virtualHostedStyle (optional boolean). Example: new S3Client({ accessKeyId: "key", secretAccessKey: "secret", bucket: "my-bucket", endpoint: "https://s3.us-east-1.amazonaws.com" })
Bun.s3 is a global S3Client singleton
Bun.s3 is a global singleton instance equivalent to new Bun.S3Client() that reads credentials from environment variables.
S3Client.file() returns lazy S3File reference
The file() method on S3Client returns a lazy reference to a file on S3. Like Bun.file(), it is synchronous and makes no network requests until you call a method that needs one.
S3File extends Blob with additional methods
S3File extends Blob, so all Blob methods work on S3File. S3File has these methods: slice(start, end), exists(), unlink(), delete(), presign(options), text(), json(), bytes(), arrayBuffer(), stream(), write(data, options), and stat(). All network methods return Promises.
S3File reading methods return same types as Blob
S3File supports reading methods: text() returns string, bytes() returns Uint8Array, json() returns JSON, arrayBuffer() returns ArrayBuffer, stream() returns ReadableStream. Memory is optimized: ASCII text is transferred directly without transcoding; bytes are not duplicated in memory.
S3File.write() accepts multiple data types
S3File.write(data, options) accepts: string, Buffer, Response, Uint8Array, ArrayBuffer, Blob, ReadableStream, or Request. The options parameter is optional and accepts type (content type), contentEncoding, and contentDisposition.
S3File.writer() for streaming uploads
S3File.writer(options) returns a writer for streaming uploads. Options include: retry (number of retries on network errors), queueSize (max concurrent requests), and partSize (chunk size in bytes). Methods: write(data), flush(), and end().
S3File.slice() uses HTTP Range header
S3File.slice(start, end) returns a partial range of the file using the HTTP Range header. This avoids downloading the entire file. It returns an S3File that can be used with text(), bytes(), or other read methods.
S3File.presign() generates signed URLs
S3File.presign(options) is synchronous and generates a presigned URL with a signature. Options: expiresIn (seconds, default 24 hours), method (GET/PUT/DELETE/HEAD/POST, default GET), acl (access control list), type (response-content-type), and contentDisposition.
S3 presign ACL values
Valid ACL values for presign: public-read (readable by public), private (owner only), public-read-write (readable and writable by public), authenticated-read (owner and authenticated users), aws-exec-read (AWS account that made request), bucket-owner-read (bucket owner), bucket-owner-full-control (bucket owner full control), log-delivery-write (AWS log delivery services).
S3 credentials from environment variables
Bun reads S3 credentials from environment variables. Primary variables: S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_REGION, S3_ENDPOINT, S3_BUCKET, S3_SESSION_TOKEN. Falls back to AWS_* equivalents if S3_* not set. Variables read from .env file or process environment at initialization time, not from process.env later.
S3Client static method: write()
S3Client.write(path, data, options) is a static method for uploading files. Options include credentials (accessKeyId, secretAccessKey, bucket, endpoint) plus type and acl. Example: await S3Client.write("my-file.txt", "Hello World", { accessKeyId: "key", secretAccessKey: "secret", bucket: "my-bucket" })
S3Client static method: presign()
S3Client.presign(path, options) generates presigned URLs. Requires credentials object with accessKeyId, secretAccessKey, and bucket. Also accepts presign options: expiresIn, method, acl, type, contentDisposition.
S3Client static method: list()
S3Client.list(options, credentials) lists objects in a bucket (up to 1000). Options: prefix (filter by key prefix), maxKeys (up to 500), fetchOwner (boolean), startAfter (for pagination). Returns object with contents array and isTruncated boolean.
S3Client static method: exists()
S3Client.exists(path, credentials) checks if an S3 file exists. Also available as instance method: await s3file.exists(). Both return Promise<boolean>.
S3Client static method: size()
S3Client.size(path, credentials) returns the size of an S3 file in bytes without downloading it. Returns Promise<number>.
S3Client static method: stat()
S3Client.stat(path, credentials) returns file metadata: etag (string), lastModified (Date), size (number), type (content type string). Returns Promise<S3Stat>.
S3Client static method: delete()
S3Client.delete(path, credentials) deletes an S3 file. S3Client.unlink() is an alias. Example: await S3Client.delete("my-file.txt", credentials) or await S3Client.unlink("my-file.txt", credentials)
S3 error codes
When Bun's S3 API throws an error, the error has a code property. Bun-specific codes: ERR_S3_MISSING_CREDENTIALS, ERR_S3_INVALID_METHOD, ERR_S3_INVALID_PATH, ERR_S3_INVALID_ENDPOINT, ERR_S3_INVALID_SIGNATURE, ERR_S3_INVALID_SESSION_TOKEN. When S3 service returns error, it is an S3Error instance (Error with name "S3Error").
S3 s3:// protocol in fetch and Bun.file()
fetch() and Bun.file() support s3:// protocol. Example: fetch("s3://my-bucket/my-file.txt") or Bun.file("s3://my-bucket/my-file.txt"). Can pass s3 options to fetch: fetch("s3://my-bucket/my-file.txt", { s3: { accessKeyId, secretAccessKey, endpoint } })
S3File UTF-8/UTF-16 handling
S3File assumes UTF-8 encoding by default. When calling text() or json(): UTF-16 BOM detected → treats as UTF-16 and strips BOM; UTF-8 BOM detected → strips BOM and replaces invalid codepoints with \uFFFD; UTF-32 not supported.
Response(S3File) redirects to presigned URL
Passing an S3File instance to Response constructor returns a 302 redirect response to a presigned URL. This avoids downloading the file to your server. Example: new Response(s3file) returns status 302 with location header containing the presigned URL.
S3 virtual hosted-style endpoints
Set virtualHostedStyle: true in S3Client constructor to use virtual hosted-style endpoints. For AWS S3: https://my-bucket.s3.us-east-1.amazonaws.com. For Cloudflare R2: https://<bucket-name>.<account-id>.r2.cloudflarestorage.com. If endpoint not specified, Bun infers it from region and bucket; defaults to us-east-1 if no region given.
S3 service providers and endpoints
Bun supports AWS S3 (default, use region or endpoint), Google Cloud Storage (endpoint: https://storage.googleapis.com), Cloudflare R2 (endpoint: https://<account-id>.r2.cloudflarestorage.com), DigitalOcean Spaces (endpoint: https://<region>.digitaloceanspaces.com), MinIO (endpoint: http://localhost:9000 or custom), Supabase (endpoint: https://<account-id>.supabase.co/storage/v1/s3/storage, requires region set).
S3 multipart upload handling
Bun automatically handles multipart uploads for large files. S3File.writer() supports retry (default 3), queueSize (default 10 concurrent requests), and partSize (default 5MB chunks) options for controlling upload behavior.
S3File.delete() and unlink() are equivalent
S3File has two methods for deletion: delete() and unlink(). They are equivalent. Example: await s3file.delete() or await s3file.unlink()
S3 example: basic file operations
Example showing basic S3 operations:
const metadata = s3.file("123.json");
const data = await metadata.json();
await write(metadata, JSON.stringify({ name: "John", age: 30 }));
const url = metadata.presign({ acl: "public-read", expiresIn: 86400 });
await metadata.delete();
S3 example: large file upload with streaming
Example showing large file upload with streaming:
const bigFile = Buffer.alloc(10 * 1024 * 1024);
const writer = s3file.writer({ retry: 3, queueSize: 10, partSize: 5 * 1024 * 1024 });
for (let i = 0; i < 10; i++) { writer.write(bigFile); await writer.flush(); }
await writer.end();