Storage
PaperDB storage lets you upload, manage, and serve files backed by Cloudflare R2 (primary) or AWS S3 (fallback). All uploads go to real object storage — files are accessible via public URLs or time-limited presigned URLs.
Storage requires R2_ACCOUNT_ID / R2_BUCKET (Cloudflare R2) or S3_BUCKET / S3_ACCESS_KEY_ID (AWS S3) to be configured on the server. Requests to unconfigured servers return 503.
Uploading Files
Upload a single file from a browser input or Node.js Blob.
const file = document.getElementById('file-input').files[0];
const result = await db.storage.upload(file, {
folder: "avatars",
isPublic: true,
metadata: { userId: "user_123" }
});
console.log("File uploaded to:", result.url);Upload Multiple Files
const results = await db.storage.uploadMany([file1, file2, file3], {
folder: "gallery",
isPublic: true
});Upload From URL
Fetch a remote file and store it directly in PaperDB. The server validates the URL against a private-IP blocklist to prevent SSRF.
const file = await db.storage.uploadFromUrl(
"https://example.com/sample-image.png",
{ folder: "imports" }
);Listing Files
const { files, total, hasMore } = await db.storage.list({
folder: "avatars",
limit: 10,
offset: 0,
sortBy: "createdAt", // "createdAt" | "name" | "size"
sortOrder: "desc" // "asc" | "desc"
});Get File Metadata
// By ID
const file = await db.storage.get("file_123");
// By storage path
const fileByPath = await db.storage.getByPath("avatars/abc123.png");Move and Copy Files
Move a file to a different folder or rename it. Copy creates a new file record at the destination path.
// Move to a different folder
const moved = await db.storage.move("file_123", {
folder: "archive",
name: "old-avatar.png" // optional rename
});
// Copy to a new location
const copy = await db.storage.copy("file_123", {
folder: "backups"
});Delete Files
// Delete single file
await db.storage.delete("file_123");
// Delete multiple files
await db.storage.deleteMany(["file_123", "file_456"]);Signed URLs
Generate a temporary presigned URL for private file access. The URL is signed by R2/S3 and expires after the specified duration.
const { url, expiresAt } = await db.storage.getSignedUrl("file_123", {
expiresIn: 3600 // seconds — default 1 hour
});Image URL with Transform Parameters
getImageUrl() appends query parameters to the CDN URL. Actual image transformation requires a CDN or image proxy (e.g., Cloudflare Images, imgproxy) configured at your R2_PUBLIC_URL or S3_PUBLIC_URL — PaperDB passes the parameters through but does not process images itself.
const url = db.storage.getImageUrl(file, {
width: 400,
height: 400,
fit: "cover",
format: "webp"
});
// → https://your-cdn.com/path/to/file?w=400&h=400&fit=cover&f=webpFolders
Folders are virtual — they are derived from the folder field on each file. You can create, list, and delete them.
// Create a folder (idempotent — safe to call multiple times)
await db.storage.createFolder("invoices/2024");
// List folders under a parent path
const folders = await db.storage.listFolders("invoices");
// Delete a folder and all files within it
const { deleted } = await db.storage.deleteFolder("invoices/old");deleteFolder() permanently deletes all files inside the folder from both the database and the storage backend. This cannot be undone.