Skip to main content

Supabase Setup

Supabase provides Krios's media storage by default. The provider abstraction means S3 / R2 / GCS work too — Supabase is just the easiest path for new deployments.

Create a Supabase project

  1. supabase.com → New project. Pick a region close to your users; matches your KRIOS_STORAGE_REGION env var.
  2. Wait for provisioning to complete.

Create a bucket

  1. Storage → New bucket.
  2. Name it krios-media (or whatever you set in SUPABASE_STORAGE_BUCKET).
  3. Visibility: Public is the simplest path for public delivery; keep it private if you need signed URLs for everything.

You can skip this step if you're fine with the defaults: Krios auto-creates the bucket as public on the first upload if it doesn't already exist. Create it manually when you want a private bucket or specific settings.

Get the service role key

Project settings → API → service_role key. Copy and set as SUPABASE_SERVICE_KEY. This key has full read/write on your project — server-side only, never expose to the client.

Set the URL

SUPABASE_URL is the project URL from the same page (e.g. https://abcdefg.supabase.co).

Image transforms

Supabase Storage's transform pipeline supports:

  • ?width=…&height=…
  • ?resize=cover|contain
  • ?format=webp|avif|jpeg
  • ?quality=…

Krios's media URL builder maps the more ergonomic params (?w=, ?h=, ?fit=, ?fp=) to Supabase's underlying syntax. Enable image transforms in Storage → Settings in the Supabase dashboard.

Bucket-level policies

For public buckets, no RLS policy is needed — Krios reads via the service role.

For private buckets:

  • Disable anonymous read.
  • Krios signs URLs server-side at delivery time (getSignedUrl(storageKey, 3600) for 1-hour-valid URLs).
  • The cache strategy: short TTL on signed URLs + edge caching by surrogate key.

Switching providers

The storage provider is plugged in at boot via src/lib/media/storage-provider.ts. To swap to S3:

import { S3StorageProvider } from "@/lib/media/storage-provider";

// In your boot file (or set via env-driven factory):
const provider = new S3StorageProvider({
bucket: process.env.S3_BUCKET!,
region: process.env.S3_REGION!,
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
});

Public-bucket reads work over the bucket's public URL. Private-bucket reads use signed URLs (getSignedObjectUrl).

Backups

Supabase Storage has built-in versioning. For larger deployments, replicate the bucket to S3 nightly via the Supabase CLI:

supabase storage cp --recursive sb://<project>/krios-media s3://backups/krios-media