Docs
Storage

Storage

Supabase Storage for AI-generated images and user file uploads.

Overview

File storage uses Supabase Storage via the @supabase/supabase-js client. The module lives in lib/supabase/storage.ts and is server-side only — it uses the service role key which bypasses Row Level Security.

Functions

uploadImageFromBase64(base64, mimeType?)

Called by the generate_image tool after OpenAI returns a b64_json response:

import { uploadImageFromBase64 } from "@/lib/supabase/storage";
 
const publicUrl = await uploadImageFromBase64(base64String, "image/png");
// Returns: "https://xxx.supabase.co/storage/v1/object/public/generated-images/abc123.png"
  • Bucket: generated-images
  • Filename: nanoid() (random, collision-safe)
  • Returns the public URL stored in the assets table

uploadFile(buffer, fileName, mimeType, bucket)

Generic upload for user-submitted files. Used for profile images, chat attachments (receipt images, PDFs, etc.):

const url = await uploadFile(pdfBuffer, "contract.pdf", "application/pdf", "uploads");
  • Bucket: uploads
  • Accepts any file type — images, PDFs, documents
  • Returns the public URL

Supabase Setup

Create a Supabase project

Sign up at supabase.com and create a new project. See the Supabase Storage docs for a full overview of buckets and access policies.

Create the storage buckets

In the Supabase dashboard, go to Storage → New bucket and create both buckets:

BucketPublicPurpose
generated-imagesYesAI-generated images from the generate_image tool
uploadsYesUser file uploads — profile images, chat attachments (receipt images, PDFs, etc.)

Copy credentials to .env

SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...

SUPABASE_SERVICE_ROLE_KEY bypasses Supabase Row Level Security. It must never be exposed to the browser or included in any NEXT_PUBLIC_ variable. All uploads happen server-side via the lib/supabase/storage.ts module.