Guides
GuideFiles & Storage

Files & Storage

Upload, manage, and serve files from secure cloud storage. Control who can access files with access rules.

Files are stored securely in the cloud. Each file gets a temporary signed download URL. Access is controlled by your app's access rules.

SDK Operations

Use the SDK in your published app pages to work with files:

// Import from the SDK
import { files } from '../api/sdk';

// List files
const fileList = await files.list();

// Upload a file (default: uploader + app owner can read)
const uploaded = await files.upload(file);

// Upload with access rules — no separate setAccessRules call needed
await files.upload(file, {
  accessRules: { read: [{ type: 'creator' }, { type: 'has_role', role: 'admin' }] },
});

// Get file metadata (also returns a 1-hour presigned download URL)
const fileMeta = await files.get(fileId);

// Get a download URL (synchronous — returns a string)
const url = files.downloadUrl(fileId);

// Get an inline URL (synchronous)
const inlineUrl = files.url(fileId);

// Delete a file
await files.delete(fileId);

files.get() returns a raw, shareable presigned URL that bypasses access rules once obtained — it's valid for 1 hour regardless of who holds it. For gated content, prefer files.url() / files.downloadUrl(), which re-check access rules on every request. Reserve files.get() for metadata or large direct-download cases.

Folders

Organize files into folders for better management. Create, rename, and delete folders from the dashboard or via the SDK.

Folder operations:

  • Create folders and subfolders
  • Move files between folders
  • Rename folders
  • Delete folders (and their contents)

Access Control

Set rules for who can upload, view, and delete files. The same rule types from Access Control apply.

FeatureDescription
Creator trackingEach upload records who uploaded the file. Use creator rules to restrict access.
Password protectionOptionally require a password to download a file.
Expiry datesSet a date after which the file can no longer be accessed.
Download restrictionAllow viewing only (inline), preventing downloads.

File Metadata

Each file stores metadata automatically:

FieldDescription
idUnique file identifier
nameOriginal file name
mimeTypeFile type (e.g., image/png, application/pdf)
sizeFile size in bytes
createdAtUpload timestamp
creatorIdID of the user who uploaded the file

Files in Backend Functions

Access files from backend functions using ctx.files:

// List files — returns { files, total }, not a bare array
const { files, total } = await ctx.files.list({ limit: 50, offset: 0 });

// Upload a small file (content must be base64-encoded, <10MB)
const { fileId } = await ctx.files.upload('report.csv', base64Content, 'text/csv');

// For files 10MB+, get a presigned upload URL instead and upload directly
const { uploadUrl, fileId: newFileId } = await ctx.files.getUploadUrl('video.mp4', 'video/mp4');

// Get download URL (presigned, valid 1 hour)
const { url } = await ctx.files.getUrl(fileId);

// Delete a file
await ctx.files.delete(fileId);

// ctx.service.files — same methods, deliberately bypasses file access rules
// (still scoped to this project). Use for owner/admin-style operations.
await ctx.service.files.list();

Download URLs from ctx.files.getUrl() are temporary, signed, and expire after 1 hour.

ctx.files.* calls are not filtered by each file's access rules the way the client-side files.* SDK calls are — any backend function already sees and can manage every file the project owns. There is no separate "bypass" call needed.