Bun’s S3 API is fast

Response and Blob APIs (like Bun’s local filesystem APIs).
- AWS S3
- Cloudflare R2
- DigitalOcean Spaces
- MinIO
- Backblaze B2
- …and any other S3-compatible storage service
Basic Usage
Bun.S3Client & Bun.s3
Bun.s3 is equivalent to new Bun.S3Client(), relying on environment variables for credentials.
To explicitly set credentials, pass them to the Bun.S3Client constructor.
Working with S3 Files
Thefile method in S3Client returns a lazy reference to a file on S3.
Bun.file(path), the S3Client’s file method is synchronous. It makes no network requests until you call a method that needs one.
Reading files from S3
S3File extends Blob, so the same methods that work on Blob also work on S3File.
Memory optimization
Methods liketext(), json(), bytes(), or arrayBuffer() avoid duplicating the string or bytes in memory when possible.
If the text happens to be ASCII, Bun transfers the string directly to JavaScriptCore (the engine) without transcoding and without duplicating it in memory. .bytes() and .arrayBuffer() also avoid duplicating the bytes in memory.
Writing & uploading files to S3
Writing to S3 works the same way.Working with large files (streams)
Bun automatically handles multipart uploads for large files and supports streaming. The same API that works for local files also works for S3 files.Presigning URLs
When your production service needs to let users upload files to your server, it’s often more reliable for the user to upload directly to S3 instead of your server acting as an intermediary. To do this, presign URLs for S3 files. Presigning generates a URL with a signature that lets a user upload that specific file to S3, without exposing your credentials or granting them unnecessary access to your bucket. By default, Bun generates aGET URL that expires in 24 hours. Bun infers the content type from the file extension; if it can’t, it defaults to application/octet-stream.
Setting ACLs
To set an ACL (access control list) on a presigned URL, pass theacl option:
| ACL | Explanation |
|---|---|
"public-read" | The object is readable by the public. |
"private" | The object is readable only by the bucket owner. |
"public-read-write" | The object is readable and writable by the public. |
"authenticated-read" | The object is readable by the bucket owner and authenticated users. |
"aws-exec-read" | The object is readable by the AWS account that made the request. |
"bucket-owner-read" | The object is readable by the bucket owner. |
"bucket-owner-full-control" | The object is readable and writable by the bucket owner. |
"log-delivery-write" | The object is writable by AWS services used for log delivery. |
Expiring URLs
To set an expiration time for a presigned URL, pass theexpiresIn option.
method
To set the HTTP method for a presigned URL, pass the method option.
new Response(S3File)
To redirect users to a presigned URL for an S3 file, pass an S3File instance to a Response object as the body.
The response redirects the user to a presigned URL for the S3 file, saving you the memory, time, and bandwidth cost of downloading the file to your server and sending it back to the user.
Support for S3-Compatible Services
Bun’s S3 implementation works with any S3-compatible storage service. Specify the appropriate endpoint:Using Bun’s S3Client with AWS S3
AWS S3 is the default. With AWS S3, you can pass aregion option instead of an endpoint option.
Using Bun’s S3Client with Google Cloud Storage
To use Bun’s S3 client with Google Cloud Storage, setendpoint to "https://storage.googleapis.com" in the S3Client constructor.
Using Bun’s S3Client with Cloudflare R2
To use Bun’s S3 client with Cloudflare R2, setendpoint to the R2 endpoint in the S3Client constructor. The R2 endpoint includes your account ID.
Using Bun’s S3Client with DigitalOcean Spaces
To use Bun’s S3 client with DigitalOcean Spaces, setendpoint to the DigitalOcean Spaces endpoint in the S3Client constructor.
Using Bun’s S3Client with MinIO
To use Bun’s S3 client with MinIO, setendpoint to the URL that MinIO is running on in the S3Client constructor.
Using Bun’s S3Client with supabase
To use Bun’s S3 client with Supabase, setendpoint to the Supabase endpoint in the S3Client constructor. The Supabase endpoint includes your account ID and the /storage/v1/s3 path. In the Supabase dashboard at https://supabase.com/dashboard/project/<account-id>/settings/storage, turn on Enable connection via S3 protocol and use the region shown in that section.
Using Bun’s S3Client with S3 Virtual Hosted-Style endpoints
When using a virtual hosted-style endpoint, set thevirtualHostedStyle option to true.
- If you don’t specify an endpoint, Bun determines the AWS S3 endpoint from the provided region and bucket. - If no
region is specified, Bun defaults to
us-east-1. - If you explicitly provide an endpoint, you don’t need to specify a bucket name.
Credentials
By default, Bun reads the following environment variables for credentials.| Option name | Environment variable |
|---|---|
accessKeyId | S3_ACCESS_KEY_ID |
secretAccessKey | S3_SECRET_ACCESS_KEY |
region | S3_REGION |
endpoint | S3_ENDPOINT |
bucket | S3_BUCKET |
sessionToken | S3_SESSION_TOKEN |
S3_* environment variable is not set, Bun falls back to the matching AWS_* environment variable.
| Option name | Fallback environment variable |
|---|---|
accessKeyId | AWS_ACCESS_KEY_ID |
secretAccessKey | AWS_SECRET_ACCESS_KEY |
region | AWS_REGION |
endpoint | AWS_ENDPOINT |
bucket | AWS_BUCKET |
sessionToken | AWS_SESSION_TOKEN |
.env files or from the process environment at initialization time (process.env is not used for this).
Options you pass to s3.file(credentials), new Bun.S3Client(credentials), or any of the methods that accept credentials override these defaults. So if you use the same credentials for different buckets, you can set the credentials once in your .env file and pass only bucket: "my-bucket" to s3.file().
S3Client objects
When you’re not using environment variables, or you’re using multiple buckets, create an S3Client object to set credentials explicitly.
S3Client.prototype.write
To upload or write a file to S3, call write on the S3Client instance.
S3Client.prototype.delete
To delete a file from S3, call delete on the S3Client instance.
S3Client.prototype.exists
To check if a file exists in S3, call exists on the S3Client instance.
S3File
Calling file() on an S3Client instance, or s3.file(), returns an S3File. Like Bun.file(), S3File instances are lazy: they don’t refer to something that necessarily exists at the time of creation. That’s why all the methods that don’t involve network requests are fully synchronous.
Bun.file(), S3File extends Blob, so all the methods available on Blob are also available on S3File. The same API that reads data from a local file also reads data from S3.
| Method | Output |
|---|---|
await s3File.text() | string |
await s3File.bytes() | Uint8Array |
await s3File.json() | JSON |
await s3File.stream() | ReadableStream |
await s3File.arrayBuffer() | ArrayBuffer |
S3File instances work with fetch(), Response, and other web APIs that accept Blob instances.
Partial reads with slice
To read a partial range of a file, use the slice method.
Range header to request only the bytes you want. This slice method is the same as Blob.prototype.slice.
Deleting files from S3
To delete a file from S3, use thedelete method.
delete is the same as unlink.
Error codes
When Bun’s S3 API throws an error, the error has acode property with one of the following values:
ERR_S3_MISSING_CREDENTIALSERR_S3_INVALID_METHODERR_S3_INVALID_PATHERR_S3_INVALID_ENDPOINTERR_S3_INVALID_SIGNATUREERR_S3_INVALID_SESSION_TOKEN
S3Error instance (an Error instance with the name "S3Error").
S3Client static methods
The S3Client class provides several static methods for interacting with S3.
S3Client.write (static)
To write data directly to a path in the bucket, use the S3Client.write static method.
new S3Client(credentials).write("my-file.txt", "Hello World").
S3Client.presign (static)
To generate a presigned URL for an S3 file, use the S3Client.presign static method.
new S3Client(credentials).presign("my-file.txt", { expiresIn: 3600 }).
S3Client.list (static)
To list some or all (up to 1,000) objects in a bucket, use the S3Client.list static method.
new S3Client(credentials).list().
S3Client.exists (static)
To check if an S3 file exists, use the S3Client.exists static method.
S3File instances.
S3Client.size (static)
To check the size of an S3 file without downloading it, use the S3Client.size static method.
new S3Client(credentials).size("my-file.txt").
S3Client.stat (static)
To get the size, etag, and other metadata of an S3 file, use the S3Client.stat static method.
S3Client.delete (static)
To delete an S3 file, use the S3Client.delete static method.
s3:// protocol
fetch and Bun.file() support the s3:// protocol, so the same code works for local files and S3 files.
s3 options to fetch and Bun.file.
UTF-8, UTF-16, and BOM (byte order mark)
LikeResponse and Blob, S3File assumes UTF-8 encoding by default.
When calling text() or json() on an S3File:
- When Bun detects a UTF-16 byte order mark (BOM), it treats the data as UTF-16. JavaScriptCore natively supports UTF-16, so Bun skips the UTF-8 transcoding step (and strips the BOM). One consequence: invalid surrogate pairs in your UTF-16 string pass through to JavaScriptCore (same as source code).
- When Bun detects a UTF-8 BOM, it strips the BOM and replaces invalid UTF-8 codepoints with the Unicode replacement character (
\uFFFD) before passing the string to JavaScriptCore. - UTF-32 is not supported.