# Backend Storage Providers for AFFiNE: File System, S3, and Cloudflare R2 Configuration

> Discover AFFiNE backend storage options File-System, AWS S3, and Cloudflare R2. Learn how to configure these providers for blobs, attachments, and user assets in your server setup.

- Repository: [Toeverything/AFFiNE](https://github.com/toeverything/AFFiNE)
- Tags: how-to-guide
- Published: 2026-03-05

---

**AFFiNE supports three backend storage providers—File-System (`fs`), AWS S3 compatible (`aws-s3`), and Cloudflare R2 (`cloudflare-r2`)—which can be configured via the server configuration to handle blobs, attachments, and user assets.**

The open-source workspace platform **toeverything/AFFiNE** abstracts its backend storage layer behind a unified `StorageProvider` interface. Understanding the available **backend storage providers for AFFiNE** is essential for self-hosting, as your choice determines where user uploads, document attachments, and avatar images persist.

## Overview of AFFiNE Storage Providers

The storage subsystem is located in `packages/backend/server/src/base/storage/` and exposes three concrete implementations registered in [`packages/backend/server/src/base/storage/providers/index.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/index.ts). Each provider implements the same `StorageProvider` interface, exposing methods like `put()`, `get()`, `list()`, and `delete()`.

### File-System Provider (`fs`)

The **File-System provider** stores objects as flat files on a local directory. It is the simplest option for development environments or single-node self-hosted deployments.

- **Identifier:** `fs`
- **Source:** [`packages/backend/server/src/base/storage/providers/fs.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/fs.ts)
- **Best for:** Local development, small deployments, or NFS-mounted volumes

### AWS S3 Compatible Provider (`aws-s3`)

The **AWS S3 compatible provider** works with any S3-compatible object storage, including AWS S3, MinIO, Ceph, and DigitalOcean Spaces. It supports multipart uploads, presigned URLs, and regional endpoints.

- **Identifier:** `aws-s3`
- **Source:** [`packages/backend/server/src/base/storage/providers/s3.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/s3.ts)
- **Best for:** Production deployments requiring scalable object storage

### Cloudflare R2 Provider (`cloudflare-r2`)

The **Cloudflare R2 provider** extends the S3 implementation to support Cloudflare R2-specific features, including optional presigned-URL handling and account-ID configuration. R2 offers S3-compatible APIs with zero egress fees.

- **Identifier:** `cloudflare-r2`
- **Source:** [`packages/backend/server/src/base/storage/providers/r2.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/r2.ts)
- **Best for:** Cost-sensitive deployments requiring global CDN integration

## How to Configure Backend Storage Providers for AFFiNE

AFFiNE reads storage configuration from the server’s `Config` object defined in [`packages/backend/server/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/config.ts). The `StorageProviderFactory` class ([`packages/backend/server/src/base/storage/factory.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/factory.ts)) instantiates the correct provider based on the `provider` field.

### Configuring the File-System Provider

Set the provider to `fs` and specify a local path. The path supports home-directory expansion using the `~` prefix.

```typescript
import { StorageProviderFactory, Config } from '@affine/server';

const cfg: Config = {
  storage: {
    provider: 'fs',
    bucket: 'affine-data',
    config: { path: '/var/affine/storage' },
  },
};

const factory = new StorageProviderFactory();
const storage = factory.create(cfg.storage);

```

### Configuring the AWS S3 Compatible Provider

Use the `aws-s3` identifier for AWS S3 or compatible services like MinIO. Provide the endpoint, region, and credentials.

```typescript
import { StorageProviderFactory, Config } from '@affine/server';

const cfg: Config = {
  storage: {
    provider: 'aws-s3',
    bucket: 'my-affine-bucket',
    config: {
      endpoint: 'https://s3.amazonaws.com',
      region: 'us-east-1',
      credentials: {
        accessKeyId: 'YOUR_ACCESS_KEY',
        secretAccessKey: 'YOUR_SECRET_KEY',
      },
    },
  },
};

const factory = new StorageProviderFactory();
const storage = factory.create(cfg.storage);

```

### Configuring the Cloudflare R2 Provider

The `cloudflare-r2` provider requires the account ID and supports optional presigned URL configuration for direct browser uploads.

```typescript
import { StorageProviderFactory, Config } from '@affine/server';

const cfg: Config = {
  storage: {
    provider: 'cloudflare-r2',
    bucket: 'my-r2-bucket',
    config: {
      endpoint: 'https://<account>.r2.cloudflarestorage.com',
      region: 'auto',
      credentials: {
        accessKeyId: 'YOUR_R2_ACCESS_KEY',
        secretAccessKey: 'YOUR_R2_SECRET_KEY',
      },
      accountId: '<CLOUDFLARE_ACCOUNT_ID>',
      usePresignedURL: {
        enabled: true,
        urlPrefix: 'https://storage.example.com',
        signKey: 'YOUR_SIGNING_KEY',
      },
    },
  },
};

const factory = new StorageProviderFactory();
const storage = factory.create(cfg.storage);

```

## Storage Provider Architecture and Source Files

AFFiNE uses a factory pattern to instantiate storage providers. The `StorageProvider` interface in [`packages/backend/server/src/base/storage/provider.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/provider.ts) defines the contract that all implementations must follow, ensuring that blob handling, attachment storage, and avatar management work transparently regardless of the backend.

Key source files implementing this architecture:

- **[`packages/backend/server/src/base/storage/providers/index.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/index.ts)** – Registers the three provider classes and exports the `StorageProviders` map and `StorageProviderConfig` type.
- **[`packages/backend/server/src/base/storage/providers/fs.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/fs.ts)** – `FsStorageProvider` implementation for local filesystem storage.
- **[`packages/backend/server/src/base/storage/providers/s3.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/s3.ts)** – `S3StorageProvider` implementation supporting any S3-compatible API.
- **[`packages/backend/server/src/base/storage/providers/r2.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/r2.ts)** – `R2StorageProvider` extending S3 with Cloudflare-specific optimizations.
- **[`packages/backend/server/src/base/storage/factory.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/factory.ts)** – `StorageProviderFactory` that creates provider instances based on configuration.
- **[`packages/backend/server/src/base/storage/provider.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/provider.ts)** – Base interface defining `put`, `get`, `list`, `delete`, and other storage operations.

## Summary

- **AFFiNE provides three backend storage providers**: File-System (`fs`), AWS S3 compatible (`aws-s3`), and Cloudflare R2 (`cloudflare-r2`).
- **Configuration is type-safe**: Set the `provider` field in the server `Config` object, and `StorageProviderFactory` instantiates the correct implementation.
- **All providers share the same interface**: Whether storing blobs on local disk or in cloud object storage, the `StorageProvider` API remains consistent across [`packages/backend/server/src/base/storage/providers/fs.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/base/storage/providers/fs.ts), [`s3.ts`](https://github.com/toeverything/AFFiNE/blob/main/s3.ts), and [`r2.ts`](https://github.com/toeverything/AFFiNE/blob/main/r2.ts).

## Frequently Asked Questions

### What is the default storage provider for AFFiNE?

The default provider depends on your deployment configuration. For local development, AFFiNE typically uses the **File-System provider** (`fs`) configured to store data in a local directory. Production deployments should explicitly configure either the `aws-s3` or `cloudflare-r2` provider in [`packages/backend/server/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/config.ts) to ensure data persistence across container restarts.

### Can I use MinIO with AFFiNE's S3 provider?

Yes. The **AWS S3 compatible provider** (`aws-s3`) works with any S3-compatible object storage, including MinIO, Ceph, and DigitalOcean Spaces. Configure the `endpoint` to point to your MinIO server (e.g., `http://localhost:9000`) and set `forcePathStyle: true` if required by your MinIO configuration.

### Does AFFiNE support Google Cloud Storage?

While AFFiNE does not ship a dedicated Google Cloud Storage (GCS) provider, you can use GCS via the **AWS S3 compatible provider** (`aws-s3`). Google Cloud Storage offers an S3-compatible interoperability mode. Configure the `endpoint` to `https://storage.googleapis.com` and use your GCS HMAC keys for the `accessKeyId` and `secretAccessKey`.

### How do I migrate data between storage providers?

AFFiNE does not currently provide an automated migration tool between storage providers. To migrate, you must manually transfer objects from the source bucket or directory to the destination using standard tools (e.g., `rclone`, `aws s3 sync`, or `rsync` for filesystem storage). After migration, update the server configuration in [`packages/backend/server/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/backend/server/src/config.ts) to point to the new provider and restart the AFFiNE server.