Quickback Docs

File Storage (R2)

Quickback provides built-in file storage using Cloudflare R2, with role-based access control and a dedicated files worker for serving.

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         Your Application                            │
│                                                                     │
│  Upload/Manage Files              Serve Files                       │
│  ─────────────────────           ──────────────                     │
│  api.yourdomain.com              files.yourdomain.com               │
│  /storage/v1/*                   /*                                 │
│                                                                     │
│  ┌─────────────────────┐         ┌─────────────────────┐           │
│  │ API Worker          │         │ Files Worker        │           │
│  │                     │         │                     │           │
│  │ POST   /bucket      │         │ GET /public/*       │           │
│  │ GET    /bucket      │         │   → No auth         │           │
│  │ POST   /object/*    │         │                     │           │
│  │ DELETE /object/*    │         │ GET /*              │           │
│  │                     │         │   → Session + RBAC  │           │
│  └──────────┬──────────┘         └──────────┬──────────┘           │
│             │                               │                       │
│             └───────────┬───────────────────┘                       │
│                         │                                           │
│                         ▼                                           │
│              ┌─────────────────────┐                                │
│              │   R2 Bucket         │                                │
│              │   quickback-files   │                                │
│              └─────────────────────┘                                │
└─────────────────────────────────────────────────────────────────────┘

Enabling File Storage

Add the fileStorage provider to your quickback.config.ts:

export default {
  name: 'my-app',
  providers: {
    runtime: { name: 'cloudflare' },
    database: { name: 'cloudflare-d1' },
    auth: { name: 'better-auth' },
    fileStorage: {
      name: 'cloudflare-r2',
      config: {
        binding: 'R2_BUCKET',
        bucketName: 'my-app-files',
        filesBinding: 'FILES_DB',
        maxFileSize: 10 * 1024 * 1024, // 10MB
        allowedTypes: ['image/jpeg', 'image/png', 'image/webp'],
      },
    },
  },
};

API Endpoints

Storage API (api.yourdomain.com/storage/v1)

MethodEndpointDescription
POST/bucketCreate a bucket
GET/bucketList buckets
GET/bucket/:nameGet bucket info
DELETE/bucket/:nameDelete bucket (must be empty)
POST/object/:bucket/*pathUpload file
GET/object/:bucket/*pathDownload file
HEAD/object/:bucket/*pathGet file metadata
DELETE/object/:bucket/*pathDelete file (soft delete)
GET/objectList objects
POST/urlGet file URL for serving

Files Worker (files.yourdomain.com)

MethodPathAuth Required
GET/HEAD/public/*No
GET/HEAD/*Yes (session + RBAC)

Buckets

Buckets organize files and define access control policies.

Creating a Bucket

POST /storage/v1/bucket
{
  "name": "avatars",
  "readScope": "organization",
  "writeScope": "organization",
  "readRoles": ["admin", "member"],
  "writeRoles": ["admin"],
  "deleteRoles": ["admin"]
}

Scope Options

ScopeRead BehaviorWrite Behavior
publicAnyone can readN/A
organizationOrg members onlyOrg members only
userOwner onlyOwner only

Role-Based Access

You can restrict operations to specific roles:

{
  "readRoles": ["admin", "member"],
  "writeRoles": ["admin", "editor"],
  "deleteRoles": ["admin"]
}

An empty array [] means no role restriction (all authenticated users).

Uploading Files

POST /storage/v1/object/avatars/profile.jpg
Content-Type: image/jpeg
Content-Length: 12345

<binary data>

Response:

{
  "id": "obj_123",
  "key": "org_abc/avatars/profile.jpg",
  "bucket": "avatars",
  "name": "profile.jpg",
  "size": 12345,
  "mimeType": "image/jpeg",
  "readScope": "organization"
}

Serving Files

Public Files

Files in buckets with readScope: "public" are stored with a public/ prefix:

https://files.yourdomain.com/public/org_abc/avatars/logo.png

No authentication required.

Private Files

Private files require a valid Better Auth session cookie:

https://files.yourdomain.com/org_abc/documents/report.pdf

The files worker:

  1. Validates the session token
  2. Checks the user's organization matches
  3. Verifies role permissions (if readRoles configured)
  4. Serves the file or returns 403

Generated Files

When file storage is configured, the compiler generates:

FilePurpose
src/routes/storage.tsStorage API routes
src/files.tsFiles database schema (buckets, objects)
cloudflare-workers/files/index.tsFiles worker for serving
cloudflare-workers/files/wrangler.tomlFiles worker config

Deployment

After compiling:

  1. Create the R2 bucket:

    wrangler r2 bucket create my-app-files
  2. Create the files database:

    wrangler d1 create my-app-files
  3. Run migrations:

    wrangler d1 migrations apply my-app-files --local
    wrangler d1 migrations apply my-app-files --remote
  4. Deploy the API:

    wrangler deploy
  5. Deploy the files worker:

    cd cloudflare-workers/files
    wrangler deploy

Configuration Reference

OptionTypeDefaultDescription
bindingstringR2_BUCKETR2 bucket binding name
bucketNamestringRequiredR2 bucket name
filesBindingstringFILES_DBFiles metadata D1 binding
maxFileSizenumber10MBMax upload size in bytes
allowedTypesstring[]Images onlyAllowed MIME types
publicDomainstring-Custom domain for files worker

Security Model

  • Upload security: Enforced by API worker (auth middleware, org check, role check)
  • Serve security: Enforced by files worker (session validation, metadata RBAC)
  • Soft deletes: Files are marked deleted in metadata but retained in R2
  • Tenant isolation: All files are prefixed with organization ID

On this page