Skip to main content
Use this guide when your app needs object storage for uploads, generated assets, or other blobs.

1. Enable Storage In floo.app.toml

[app]
name = "crm"

[storage]

[services.web]
type = "web"
path = "."
port = 3000
ingress = "public"

2. Ship The First Deploy

floo preflight --json
floo apps github connect owner/repo --app my-app
floo deploys watch --app my-app
The first real deploy provisions the bucket and injects the storage env vars into the app environment.

3. Verify The Env Vars

When Floo-managed storage is provisioned for an app, the backend injects:
  • STORAGE_BUCKET — the name of the provisioned storage bucket
  • STORAGE_URL — the signed URL API endpoint your app POSTs to for time-limited upload/download URLs
Those are the env vars to document and consume.
floo env list --app my-app --json 2>/dev/null | jq '.data.env_vars[] | select(.key == "STORAGE_BUCKET" or .key == "STORAGE_URL")'
floo env get STORAGE_BUCKET --app my-app
floo env get STORAGE_URL --app my-app

4. Use Signed URLs In App Code

Your app never talks to the storage provider directly. Instead, POST to STORAGE_URL to get a time-limited signed URL, then upload or download using that URL. The signed URL endpoint requires your Floo API key — call it from your backend, not from browser code. Request shape:
{
  "method": "PUT",
  "object_path": "uploads/avatar.png",
  "content_type": "image/png",
  "expiration_seconds": 3600
}
Use "method": "PUT" for uploads and "method": "GET" for downloads. content_type is required for PUT requests. The response includes a url field your app uses for the actual transfer.
const storageUrl = process.env.STORAGE_URL;

// Get a signed upload URL
const res = await fetch(storageUrl, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    method: "PUT",
    object_path: "uploads/avatar.png",
    content_type: "image/png",
    expiration_seconds: 3600,
  }),
});

const { url } = await res.json();

// Upload the file to the signed URL
await fetch(url, {
  method: "PUT",
  headers: { "Content-Type": "image/png" },
  body: fileBuffer,
});

5. Debugging Checklist

If uploads or downloads fail:
floo env get STORAGE_BUCKET --app my-app
floo env get STORAGE_URL --app my-app
floo logs --app my-app --error --since 30m
Look for:
  • missing env vars
  • wrong bucket name assumptions in code
  • signed URL request failures or expiration errors in runtime logs

Managed Services Setup

See the exact floo.app.toml shape for storage and other managed services.

Environment Variables

See how env inspection works after the bucket is provisioned.