Skip to content

File Storage

Butterbase provides file storage with presigned URLs. Files are organized per-app and per-user. Your frontend uploads and downloads files directly — file data never flows through your backend code.

  1. Request an upload URL — Your app asks Butterbase for a presigned upload URL, providing the filename, content type, and size.
  2. Upload directly — Your frontend uses the presigned URL to upload the file directly to storage.
  3. Reference the file — Store the returned objectId in your database (e.g., as an image_url column).
  4. Download when needed — Request a presigned download URL using the object ID.
ValueWhat it isWhat to do with it
objectIdA stable UUID for this filePersist this in your database. Use it for downloads and deletes.
objectKeyThe path inside the bucketNot a URL. Metadata only; do not store for display.
uploadUrl / downloadUrlTemporary presigned HTTPS URLsUse only for immediate operations. They expire.
  • Saving objectKey as a URL — It’s a path, not a URL. The UI will show broken images.
  • Using objectKey as img src — Use objectId with the download endpoint to get a downloadUrl.
  • Storing only a presigned URL — Presigned URLs expire. Store objectId as the source of truth.

Step 1: Request the upload URL.

POST /storage/{app_id}/upload
Authorization: Bearer {token}
{
"filename": "profile.jpg",
"contentType": "image/jpeg",
"sizeBytes": 102400
}

Response:

{
"uploadUrl": "https://storage.example.com/...",
"objectKey": "app_id/user_id/uuid_profile.jpg",
"objectId": "uuid",
"expiresIn": 300
}

Step 2: Upload the file using the presigned URL.

await fetch(uploadUrl, {
method: 'PUT',
headers: { 'Content-Type': 'image/jpeg' },
body: fileBlob
});

Step 3: Save the objectId in your database.

GET /storage/{app_id}/download/{object_id}
Authorization: Bearer {token}

Response:

{
"downloadUrl": "https://storage.example.com/...",
"filename": "profile.jpg",
"expiresIn": 3600
}

After loading rows that reference stored files by objectId:

  1. For each file, call the download API or SDK getDownloadUrl(objectId).
  2. Use the returned downloadUrl as <img src> or download link.
  3. For lists, resolve download URLs in parallel (Promise.all) for speed.
GET /storage/{app_id}/objects
Authorization: Bearer {token}

Returns an array of objects with id, filename, content_type, size_bytes, and created_at.

LimitDefault
Max file size10 MB per file
Total storage1 GB per app
Allowed content typesAll types (configurable)
  • Service key: Full access to all files. Uploads have no user association.
  • End-users: Can only see and manage their own files. Uploads are automatically associated with the authenticated user.
  • Upload URLs expire after 5 minutes
  • Download URLs expire after 1 hour
const { data } = await butterbase.storage.upload(file);
const { data: url } = await butterbase.storage.getDownloadUrl(objectId);
const { data: objects } = await butterbase.storage.list();
await butterbase.storage.delete(objectId);