File Storage

Store user files with access rules built in

Upload directly from your app, keep files private by default, and share individual files through public URLs.

File Storage product screenshot
storage
volcano cloud storage bucket create user-files --file-size-limit 26214400✓ user-files created · objects private by defaultvolcano cloud storage policy create user-files --name own-read \  --operation SELECT --definition "auth.uid() = owner_id"✓ policy own-read · SELECTvolcano cloud storage object upload user-files ./report.pdf 8f1c/report.pdf✓ uploaded 4.2 MB · privatevolcano cloud storage object visibility user-files 8f1c/report.pdf --publicis_public true · served from its public URL# every other object in the bucket still needs an authorized request
Overview

Handle uploads without a signing service

User uploads need more than somewhere to land. Each user needs access to the right files, and publishing a report should leave the files beside it private.

Volcano stores files as objects in per-project buckets. The browser uploads with the user’s session, bucket policies decide access with auth.uid(), and size and file-type limits run on the server.

File access

Keep each user’s files behind a policy

Use auth.uid() = owner_id for owner-only reads, or match the path to the user’s ID for uploads. Policies are written like Postgres row-level security, and storage enforces them on every request.

  • Separate rules for SELECT, INSERT, UPDATE and DELETE
  • Match the owner, path or file extension
  • Multiple policies per operation; any match grants access
volcano cloud storage policy
# owner-only reads, written as one SQL expressionvolcano cloud storage policy create user-files --name own-read \  --operation SELECT --definition "auth.uid() = owner_id"✓ policy own-readvolcano cloud storage policy list user-filesown-read SELECT · own-write INSERT · own-delete DELETE
File sharing

Publish one file without opening the bucket

Set is_public on a file to give it a public URL. Other files in the bucket keep their own visibility settings.

  • New objects start with is_public set to false
  • updateVisibility changes one file’s visibility
  • Public objects include a public_url in the response
volcano.dev/dashboard/file-storage
Objects in a bucket, each with its own visibility
Resumable uploads

Resume a large upload from the missing parts

Save the upload session ID so a dropped connection does not mean starting over. Sessions last seven days. Call getUploadSession to find the stored parts, then upload only what is missing.

  • Choose 5–25 MB parts; the last can be smaller
  • Upload parts in any order
  • Up to 100 MB per file on Hobby or 10 GB on Superagent
a Superagent upload session, resumed
createUploadSession('8f1c/keynote.mp4', { totalSize: file.size })session s_7f2 · 74 parts of 25 MBpart 38/74   ← connection droppedgetUploadSession('8f1c/keynote.mp4', 's_7f2')parts_uploaded: 37 of 74✓ 37 parts sent · 1.8 GB object ready
Capabilities

File storage for your app

Buckets per project

Organize files into buckets with their own policies and limits.

Private by default

New files need an authorized request to read them.

Per-user access

Write per-operation policies against auth.uid(), the same helper your table policies use.

Browser uploads

Send a File, Blob or ArrayBuffer through the SDK using the user’s session.

Multipart uploads

Manage upload sessions yourself, or use uploadResumable for chunking and progress.

Upload limits

Set a size limit and allowed MIME types, such as image/png, for each bucket.

Code

Upload, protect and manage files

TypeScript
import { VolcanoAuth } from '@volcano.dev/sdk'; const volcano = new VolcanoAuth({ apiUrl: process.env.NEXT_PUBLIC_VOLCANO_API_URL!, anonKey: process.env.NEXT_PUBLIC_VOLCANO_ANON_KEY!, }); const bucket = volcano.storage.from('user-files'); export async function uploadForUser(userId: string, file: File) { const path = userId + '/' + file.name; // Anything sizeable goes up in parts, with progress. uploadResumable gives // up on the first failed part; to resume later, keep the session id and use // createUploadSession, getUploadSession and uploadPart instead. if (file.size > 100 * 1024 * 1024) { return bucket.uploadResumable(path, file, { partSize: 8 * 1024 * 1024, onProgress: (sent, total) => setPercent(Math.round((sent / total) * 100)), }); } // File, Blob or ArrayBuffer. Not a Node Buffer and not a stream. return bucket.upload(path, file, { contentType: file.type }); }
Use cases

What people store in it

two requests, one policy
upload user-files/8f1c/avatar.png    (session 8f1c…)200  storedupload user-files/9a2b/avatar.png    (session 8f1c…)403  policy deniedthe storage layer decided, not the client
Platform

Works with the rest of Volcano

Authentication
  • Authentication for file access

    Use the signed-in user’s ID in storage policies and Postgres policies through the same auth.uid() helper.

Databases and vector
  • File metadata in Postgres

    Store file descriptions in Postgres and apply matching owner checks to rows and objects.

Functions and agents
  • Functions for file processing

    Download an uploaded file inside a function, process it, and write the result to a bucket.

Next.js frontends
  • Files in your Next.js app

    Display public files by URL and use the caller’s session to read private files.

Frequently asked questions

Read the docs
How do I keep uploaded files private?

Files are private by default; add a SELECT policy to allow the intended users to read them. For owner-only reads, use auth.uid() = owner_id. Service keys bypass policies, so keep them on the server.

Can I upload files directly from the browser?

Yes, the JavaScript SDK uploads directly using the user’s session, without a signing endpoint. Pass a File, Blob or ArrayBuffer to upload(). Storage checks your bucket policies on the request.

What is the maximum file upload size?

The maximum is 100 MB per file on Hobby or 10 GB on Superagent. A lower bucket limit or the account’s storage allowance can also restrict uploads.

How do I resume an interrupted file upload?

Keep the upload session ID and call getUploadSession to find which parts arrived. Send the missing parts with uploadPart, then call completeUploadSession.

How do I share a private file with a public URL?

Call updateVisibility(path, true) from the SDK, or volcano cloud storage object visibility <bucket> <path> --public from the CLI. The response includes the object’s public_url, which needs no token. Publishing needs an UPDATE policy that allows it, or a service key. Cached copies can stay reachable for up to five minutes after a file goes private.

Can I restrict upload size and file types?

Yes, each bucket can set a file size limit and an allowed MIME type list. Volcano enforces both on the server, so the checks also apply to requests sent outside your upload form.

Add file storage to your app

Build, deploy, and scale on Volcano's global platform — free to start, with no infrastructure to manage.

Checkout more features