Labels.io

File uploads

The kit ships file uploads built in. /app/files has a dropzone and a file grid. Until you add storage credentials it runs in demo mode — picked files are added to the list locally and nothing is stored. Add an S3-compatible bucket and picks upload for real.

One config works with AWS S3, DigitalOcean Spaces, Cloudflare R2, or Supabase Storage — they all speak the S3 API. Uploads go through the app's server (browser → your server → bucket), so there is no bucket CORS to configure. Files are namespaced per signed-in user.

1. Add storage credentials

Copy this block into .env and fill in the values for your provider:

STORAGE_BUCKET=uploads
STORAGE_REGION=auto                 # AWS/DO/Supabase: real region · R2: auto
# STORAGE_ENDPOINT=                 # blank for AWS S3; set for DO / R2 / Supabase
STORAGE_ACCESS_KEY_ID=
STORAGE_SECRET_ACCESS_KEY=
STORAGE_FORCE_PATH_STYLE=false      # true for Supabase Storage (and MinIO)
# STORAGE_PUBLIC_URL=              # public/CDN base URL for reading files (optional)

If any of STORAGE_BUCKET, STORAGE_ACCESS_KEY_ID, or STORAGE_SECRET_ACCESS_KEY is missing, the kit stays in demo mode.

2. Per-provider settings

Fill the same keys differently depending on where your bucket lives:

ProviderSTORAGE_ENDPOINTSTORAGE_REGIONSTORAGE_FORCE_PATH_STYLE
AWS S3(leave blank)the bucket's real region, e.g. us-east-1false
Cloudflare R2https://<accountid>.r2.cloudflarestorage.comautofalse
DigitalOcean Spaceshttps://<region>.digitaloceanspaces.comthe Space's region, e.g. nyc3false
Supabase Storagehttps://<project-ref>.storage.supabase.co/storage/v1/s3the project regiontrue

Create the bucket in your provider's dashboard, generate an access key + secret, and paste them into STORAGE_ACCESS_KEY_ID / STORAGE_SECRET_ACCESS_KEY.

3. Reading files back

  • Private bucket (default): the kit generates short-lived signed URLs (about 1 hour) so the file grid can preview/download — nothing else is needed.
  • Public bucket / CDN: set STORAGE_PUBLIC_URL to your public base URL (for example a CloudFront or R2 public domain) and the grid links straight to it.

4. Test the setup

  1. Restart the dev server after editing .env.
  2. Open /app/files and drop a file onto the dropzone.
  3. The file uploads through the server and appears in the grid.
  4. Check your provider's dashboard — the object is under uploads/<your-user-id>/….
  5. Reload the page; the grid lists the file from storage (not the demo seed).

Production checklist

Before going live:

  • Use a dedicated bucket and an access key scoped to just that bucket.
  • Decide private (signed URLs) vs public (STORAGE_PUBLIC_URL) and set it consistently.
  • Set a sensible max object size / lifecycle policy in your provider if you expect large files.

Useful docs:

On this page