Storage
Volcano Storage provides durable object storage with RLS-style access control policies.
Volcano Storage provides durable object storage with RLS-style access control policies. Store user files, images, documents, and any binary data with automatic per-user isolation.
Features
| Feature | Description |
|---|---|
| Durable | Files are stored redundantly and served through the Volcano API |
| RLS policies | Fine-grained access control per object |
| Per-project | Each project has isolated storage namespaces |
| Buckets | Organize files into logical buckets |
| File limits | Set per-bucket file size and MIME type restrictions |
| SDK support | Full JavaScript/TypeScript SDK for browser and Node.js |
Quick example
Upload a file
import { VolcanoAuth } from '@volcano.dev/sdk';
const volcano = new VolcanoAuth({
apiUrl: 'https://api.yourapp.com',
anonKey: 'your-anon-key',
});
// Sign in first
await volcano.auth.signIn({ email: 'user@example.com', password: 'password' });
// Upload a file
const file = document.querySelector('input[type="file"]').files[0];
const { data, error } = await volcano.storage.from('avatars').upload('profile.jpg', file);
if (error) {
console.error('Upload failed:', error.message);
} else {
console.log('Uploaded:', data.name);
}Download a file
const { data, error } = await volcano.storage.from('avatars').download('profile.jpg');
if (!error) {
// data is a Blob
const url = URL.createObjectURL(data);
img.src = url;
}List files
const { data: files, error } = await volcano.storage.from('documents').list('user/reports/');
files.forEach((file) => {
console.log(`${file.name} - ${file.size} bytes`);
});Range downloads
A byte range that starts at or beyond the end of a file returns HTTP 416 with
{"error":"requested range not satisfiable"}. When the current file size is
available, Content-Range: bytes */size reports it. This applies to authenticated
and public downloads. Invalid range syntax returns HTTP 400.
Storage failures
Unexpected storage failures return HTTP 500 with an operation-specific error
message, without internal diagnostic details. Listing object records returns
{"error":"failed to list objects"}; fetching file content returns
{"error":"failed to download file"}. Earlier bucket, policy, or object metadata
lookups can return different messages.
Access control
Storage uses RLS-style policies to control access. By default, without policies, all access is denied.
Common policies
-- Users can only access their own files
CREATE POLICY "owner_access" ON storage_objects
FOR ALL USING (auth.uid() = owner_id);
-- Anyone can view files in the public folder
CREATE POLICY "public_read" ON storage_objects
FOR SELECT USING (name LIKE 'public/%');
-- Users can only upload to their own folder
CREATE POLICY "user_folder" ON storage_objects
FOR INSERT USING ((storage.foldername(name))[1] = auth.uid()::text);Policies are defined per-bucket and support:
SELECT- Read/download filesINSERT- Upload new filesUPDATE- Overwrite existing filesDELETE- Remove files
See Storage Policies for complete examples.
Buckets
Buckets organize your files into logical groups. Each bucket can have:
- File size limit - Maximum file size in bytes
- Allowed MIME types - Restrict to specific file types
- Access policies - Control who can read, write, update, and delete files
// Create a bucket via API
const response = await fetch('/storage/buckets', {
method: 'POST',
headers: {
Authorization: `Bearer ${serviceKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'user-uploads',
file_size_limit: 10 * 1024 * 1024, // 10MB
allowed_mime_types: ['image/jpeg', 'image/png', 'image/gif'],
}),
});See Buckets for more details. For CLI workflows, see the Volcano CLI docs.
Storage limits
Your plan sets the account-wide storage allowance and maximum object size. See Plans and limits for current values.
Error codes for file size violations:
413- Plan-based storage quota exceeded or plan-based file size limit exceeded400- Bucket-levelfile_size_limitexceeded, MIME type not allowed, or file exceeds the global 10 GB limit
Bandwidth
Every storage request counts toward your account's billing-cycle bandwidth
allowance, in both directions: uploads, downloads, public file serving, and
list, copy, move, delete, and visibility requests. The allowance is shared by all
your projects; see Plans and limits. On
HOBBY, once it is spent, storage requests are rejected with 429 until the next
allowance window or an upgrade.
File visibility
Files are private by default. You can make individual files public:
// Make a file public
await volcano.storage.from('files').updateVisibility('report.pdf', true);
// Get a shareable public URL (no authentication required)
const { data } = volcano.storage.from('files').getPublicUrl('report.pdf');
console.log(data.publicUrl);
// https://api.yourapp.com/public/{projectId}/files/report.pdf
// This URL can be shared anywhere - no SDK needed!Public and private files can coexist in the same bucket. Only the file owner
(or a service key) can change visibility. Configured UPDATE policies also
apply to owner visibility changes.
Authenticated downloads use Cache-Control: private, no-store.
Public downloads can be cached by browsers and shared caches for up to five
minutes. Visibility changes and deletions can therefore take up to five minutes
to propagate to clients that already cached the file.
SDK methods
The JavaScript SDK provides these methods:
| Method | Description |
|---|---|
from(bucket) | Select a bucket for operations |
upload(path, file) | Upload a file (private by default) |
download(path) | Download a file as Blob |
list(prefix) | List files with optional prefix |
remove(paths) | Delete one or more files |
move(from, to) | Move/rename a file |
copy(from, to) | Copy a file |
updateVisibility(path, isPublic) | Make file public or private |
getPublicUrl(path) | Get shareable public URL (no auth needed) |
See JavaScript SDK for the complete reference.
REST API
All storage operations are also available via REST API:
| Method | Endpoint | Description |
|---|---|---|
POST | /storage/{bucket}/{path} | Upload file |
GET | /storage/{bucket}/{path} | Download file |
DELETE | /storage/{bucket}/{path} | Delete file |
GET | /storage/{bucket} | List files |
POST | /storage/{bucket}/move | Move file |
POST | /storage/{bucket}/copy | Copy file |
PATCH | /storage/{bucket}/{path}/visibility | Set public/private |
GET | /public/{projectId}/{bucket}/{path} | Download public file (no auth) |
See Storage API Reference for complete documentation.
What's next
| Guide | Description |
|---|---|
| JavaScript SDK | Complete SDK reference |
| Storage Policies | Access control with RLS-style policies |
| Buckets | Creating and managing buckets |
| API Reference | REST API endpoints |