---
title: Appwrite
description: 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.

```package-install
files-sdk node-appwrite
```

## Usage

```ts lineNumbers
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 be alphanumeric/dashes
    // and max 36 chars. Slashes (/) are not supported.
  }),
});
```

## Options

<AutoTypeTable
  path="../../packages/files-sdk/src/appwrite/index.ts"
  name="AppwriteAdapterOptions"
/>

## Limitations

File IDs (keys) must start with an alphanumeric and use only `[a-zA-Z0-9._-]`, max 36 characters (no slashes) - invalid keys are rejected 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.

## 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. |
| `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. |
| `url` | ⚠️ | Throws by default because Appwrite SDKs cannot mint presigned reading URLs with keys. Set `public: true` at construction to return the constructed Appwrite public CDN URL. `expiresIn` and `responseContentDisposition` are ignored. |
| `signedUploadUrl` | ❌ | No presigned upload primitive in Appwrite. Use JWTs or client SDKs for direct uploads. |
