Appwrite
Appwrite Storage via the official node-appwrite SDK. Auto-loads APPWRITE_ENDPOINT, APPWRITE_PROJECT_ID, and APPWRITE_API_KEY, or pass an existing client.
Installation
node-appwrite is an optional peer dependency of files-sdk - install alongside the SDK so the adapter’s imports resolve at runtime.
npm install files-sdk node-appwritepnpm add files-sdk node-appwriteyarn add files-sdk node-appwritebun add files-sdk node-appwritenub add files-sdk node-appwriteaube add files-sdk node-appwriteUsage
import { Files } from "files-sdk";
import { appwrite } from "files-sdk/appwrite";
const files = new Files({
adapter: appwrite({
bucket: "uploads",
// Auto-loads from APPWRITE_ENDPOINT, APPWRITE_PROJECT_ID,
// and APPWRITE_API_KEY. Or pass an existing node-appwrite
// Client or Storage instance via `client`.
//
// Note: Appwrite keys (IDs) must start with a letter or digit,
// use only [a-zA-Z0-9._-], and be at most 36 chars.
// Slashes (/) are not supported.
}),
});
Options
bucketstring
Appwrite storage bucket ID.
stringclient?Client | Storage
Existing client instance or Storage instance. Highest precedence.
Client | Storageendpoint?string
Appwrite API endpoint (e.g. `https://cloud.appwrite.io/v1`). Falls back to `APPWRITE_ENDPOINT` then `NEXT_PUBLIC_APPWRITE_ENDPOINT`.
stringprojectId?string
Appwrite Project ID. Falls back to `APPWRITE_PROJECT_ID` then `NEXT_PUBLIC_APPWRITE_PROJECT_ID`.
stringkey?string
Appwrite API Key. Falls back to `APPWRITE_API_KEY` then `APPWRITE_KEY`.
stringpublic?boolean
Set to `true` if the bucket is configured as a public bucket. `url()` will then return a constructed permanent, unsigned URL (the `/view` endpoint, or `/download` for `responseContentDisposition: "attachment"`; any other disposition throws). Otherwise, `url()` throws an error.
booleanLimitations
File IDs (keys) must start with an alphanumeric and use only [a-zA-Z0-9._-], max 36 characters (no slashes) - every method that takes a key rejects an invalid one before the API call. list({ prefix }) queries startsWith("$id", ...) against the canonical file ID, so files created outside the adapter where the display name differs from $id won’t be matched by prefix. Resumable uploads (control) send chunks over Appwrite’s REST API with the API key, so they need key (or APPWRITE_API_KEY); an adapter built from a pre-built client throws on them.
Compatibility
| Method | Status | Notes |
|---|---|---|
upload |
⚠️ | Stream bodies are buffered up-front - InputFile.fromBuffer has no streaming form, so streamed uploads can’t avoid materializing the body in memory. User metadata and cacheControl throw - Appwrite’s createFile has no equivalent fields. contentType is silently ignored - Appwrite auto-detects mime from the payload and has no override. Uploading onto an existing key replaces the file by deleting it and creating it again (Appwrite can’t update a file’s content): not atomic, and file-level permissions on the old file aren’t carried over. Resumable uploads (control) don’t replace: Appwrite rejects a chunked upload onto an existing file ID, so delete the key first. |
download |
✅ | |
delete |
✅ | |
list |
✅ | |
search |
✅ | |
head |
✅ | |
exists |
✅ | |
copy |
⚠️ | Read-then-write - Appwrite has no server-side copy primitive, so the source is downloaded and re-uploaded. Costs an egress + an ingest; not atomic. An existing destination is replaced the same way upload replaces one. |
url |
⚠️ | Throws by default because Appwrite SDKs cannot mint presigned reading URLs with keys. Set public: true at construction to return the constructed, permanent Appwrite /view URL. expiresIn is ignored. responseContentDisposition: "attachment" returns the /download URL (served as an attachment named after the stored file name); any other disposition, such as a custom filename or inline, throws - Appwrite has no per-request override. |
signedUploadUrl |
❌ | No presigned upload primitive in Appwrite. Use JWTs or client SDKs for direct uploads. |