Announcing the S3 API: Use any S3 client with Appwrite Storage_
Appwrite Storage now exposes an S3-compatible API. Point the AWS CLI, the AWS SDKs, and tools like rclone at your Appwrite buckets, with no migration required.

The S3 API has become the common language of object storage. The AWS CLI, the AWS SDKs, backup tools like rclone and s3cmd, data pipelines, and countless libraries all speak it. Until now, using them with Appwrite Storage meant writing glue code around the native API.
Today, we are announcing the S3 API for Appwrite Storage, an S3-compatible API that lets you point any S3 client, SDK, or tool at your Appwrite buckets and files.
The API uses AWS Signature Version 4 and maps standard S3 operations onto Appwrite Storage, so most existing S3 code works after you change three settings: the endpoint, the credentials, and the region.
Why this matters
Appwrite Storage already gives you buckets, permissions, image transformations, and file tokens through the native API and SDKs. The S3 API adds a second door into the same storage, unlocking the whole S3 ecosystem:
- Bring your existing tools. Use the AWS CLI, rclone, s3cmd, and any S3-aware library or service against Appwrite buckets without glue code.
- Reuse existing code. Applications already written against the AWS SDKs connect to Appwrite by changing the client configuration, not the code.
- No migration required. Buckets and files are addressable over both the native Storage API and the S3 API at the same time. Files uploaded over S3 show up in the Appwrite Console, and files uploaded through the Console or SDKs are listable and downloadable over S3.
- Multipart uploads out of the box. SDK transfer managers and
aws s3 cpupload large files in parts automatically, with the standard multipart operations fully supported. - Hand out access without handing out credentials. Sign a presigned URL on your server and give it to a browser, a mobile app, or a partner. It grants one operation on one object, expires on a schedule you set, and never exposes your API key.
How it works
S3 clients authenticate with an access key ID and a secret access key. Appwrite maps these to your project ID and an API key secret:
| Setting | Value |
|---|---|
| Endpoint | https://<REGION>.cloud.appwrite.io/v1/s3 |
| Access key ID | Your Appwrite project ID |
| Secret access key | An Appwrite API key secret |
| Region | auto or your project's Appwrite region |
| Signature version | AWS Signature Version 4 (SigV4) |
| Addressing style | Path-style only |
The API key's scopes control what the client can do: grant buckets.read and files.read for read-only workloads, and add buckets.write and files.write for uploads, deletes, and bucket creation.
Here is the same configuration in the AWS CLI, the AWS SDK for JavaScript, and boto3:
Once the client is configured, everyday S3 commands work as usual:
# Create a bucketaws s3api create-bucket --bucket my-bucket \ --endpoint-url https://<REGION>.cloud.appwrite.io/v1/s3
# Upload a file (uses multipart automatically for large files)aws s3 cp ./january.pdf s3://my-bucket/reports/january.pdf \ --endpoint-url https://<REGION>.cloud.appwrite.io/v1/s3
# List objectsaws s3 ls s3://my-bucket --recursive \ --endpoint-url https://<REGION>.cloud.appwrite.io/v1/s3
# Download an object by its keyaws s3 cp s3://my-bucket/reports/january.pdf ./january.pdf \ --endpoint-url https://<REGION>.cloud.appwrite.io/v1/s3S3 objects, Appwrite files
S3 buckets map directly to Appwrite Storage buckets, and S3 objects map to files. Object keys are file names, used directly: uploading to reports/january.pdf stores a file named reports/january.pdf, and read, copy, and delete operations address that object by the same key. Nothing has to be looked up first, so files created through the native Storage API or the Console are usable over S3 under the names they already have.
Because the key is the name, a key addresses exactly one object: uploading to a key that already exists overwrites it, the way S3 does, reusing the existing file so it keeps its Appwrite file ID and permissions. Storage itself does let several files in a bucket share a name, but the S3 API cannot address those, so if your workload depends on repeating file names in one bucket, the native Storage API, which addresses files by ID, remains the right interface for it.
Folders work the way they do on S3 itself: they are virtual, existing as /-separated prefixes in object keys. List a bucket with the / delimiter and an optional prefix to browse it like a directory tree, with folders grouped under CommonPrefixes and files under Contents.
Share objects with presigned URLs
Not every client should hold an API key. A presigned URL carries its AWS Signature Version 4 authentication in the query string instead of a header, so you can sign one on your server and hand it to a client that has no Appwrite credentials at all.
// On your server: sign a URL the browser can upload toimport { PutObjectCommand } from '@aws-sdk/client-s3';import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const uploadUrl = await getSignedUrl( client, new PutObjectCommand({ Bucket: 'my-bucket', Key: 'reports/january.pdf', ContentType: 'application/pdf' }), { expiresIn: 900 });The signature covers the HTTP method, the object key, and every other query parameter, so the URL authorizes exactly one request. A URL signed for a download cannot be replayed as an upload, and changing the key invalidates it. You choose the lifetime when you generate it, anywhere from a second up to 7 days.
The standard helpers all work: getSignedUrl in the AWS SDK for JavaScript, generate_presigned_url in boto3, and createPresignedRequest in the AWS SDK for PHP, along with aws s3 presign, rclone link, and s5cmd presign.
The endpoint also answers cross-origin requests from any origin and handles preflight, so a presigned URL works directly from browser JavaScript. A web page can upload straight to a presigned PutObject URL or stream a Range request out of an object with no proxy in between, and response headers like ETag, Content-Range, and Last-Modified are exposed to client code.
What's supported
The S3 API targets the operations most clients depend on:
- Bucket operations:
ListBuckets,CreateBucket,HeadBucket,DeleteBucket, andGetBucketLocation - Object operations:
PutObject,GetObject(withRangeand conditional requests),HeadObject,CopyObject,DeleteObject,DeleteObjects,ListObjects, andListObjectsV2 - Multipart uploads: the full flow, from
CreateMultipartUploadthroughUploadPart,UploadPartCopy,CompleteMultipartUpload,AbortMultipartUpload,ListMultipartUploads, andListParts - Presigned URLs: sign any supported operation into a URL, valid for up to 7 days, and use it from any client, including a browser
Buckets keep their constraints under the S3 API: uploads that exceed the bucket's maximum file size or use a disallowed extension are rejected, and access is governed by Appwrite permissions and API key scopes. Features outside this set, such as object tagging, lifecycle rules, bucket policies, and versioning, return standard NotImplemented errors, so clients fail cleanly. The full list is in the limitations documentation.
Get started
The S3 API is available on Appwrite Cloud today.
- Navigate to Overview > Integrations > API keys and create an API key with the storage scopes your workload needs.
- Configure your S3 client with the
https://<REGION>.cloud.appwrite.io/v1/s3endpoint, your project ID as the access key ID, and the API key secret as the secret access key. - Run your existing S3 commands and code against your Appwrite buckets.
- To reach clients that have no Appwrite credentials, sign a presigned URL on your server and hand it to them.
Full documentation, including folder listings, file name rules, and error responses, is available on the S3 API documentation page.





