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.
| Feature | Description |
|---|---|
| Creator tracking | Each upload records who uploaded the file. Use creator rules to restrict access. |
| Password protection | Optionally require a password to download a file. |
| Expiry dates | Set a date after which the file can no longer be accessed. |
| Download restriction | Allow viewing only (inline), preventing downloads. |
File Metadata
Each file stores metadata automatically:
| Field | Description |
|---|---|
| id | Unique file identifier |
| name | Original file name |
| mimeType | File type (e.g., image/png, application/pdf) |
| size | File size in bytes |
| createdAt | Upload timestamp |
| creatorId | ID 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.