Skip to content

file storage · side by side

Supabase Storage vs Vercel Blob for a Next.js app

Both fill the file storage slot, so a generated repo carries one or the other, never both. Every line below is read out of the two manifests.

Short answer

Pick Supabase Storage if

Teams already on Supabase who want files under the same policies as their rows. Same migrations, same pull request. Strongest for private per-user files (avatars, invoices, imports) where "the owner and nobody else" is the whole access model.

Pick Vercel Blob if

Apps already on Vercel that want user uploads (avatars, attachments, imports) without adding a cloud account, IAM, CORS rules or a second bill. Strongest when files are small to medium and read by their owner.

Vercel Blob is tested with Neon. Supabase Storage isn't yet.

Side by side

Price, obligations, and the surface each one adds. No row is written by hand. This is manifest.yaml, rendered.

Supabase Storage compared with Vercel Blob on pricing, fit, trade-offs, required companions, environment variables, dependencies, MCP servers and repo footprint.
From the manifestOption ASupabase StorageOption BVercel Blob
In one lineSupabase Storage

Object storage in your Supabase project, with the same row level security as tables.

Vercel Blob

File storage inside your Vercel project. One env var to wire, no second vendor.

PricingSupabase Storage

Part of your Supabase plan. Free: 1 GB stored and 5 GB egress. Pro: 100 GB stored, then $0.0213/GB, and 250 GB egress, then $0.09/GB ($0.03/GB for cached egress). Image transformations need Pro: 100 origin images included, then $5 per 1,000.

Vercel Blob

Hobby: free up to 1 GB stored, 10,000 simple and 2,000 advanced operations, and 10 GB of transfer a month. Past the limit, Blob stops until the 30 days reset. Pro bills by usage. Prices below are for iad1. Storage is $0.023 per GB-month and transfer $0.05 per GB. Simple operations (cache-miss reads) are $0.40 per million. Advanced operations (put, copy, list) are $5 per million. Deletes are free. Client uploads have no transfer charge.

Best forSupabase Storage

Teams already on Supabase who want files under the same policies as their rows. Same migrations, same pull request. Strongest for private per-user files (avatars, invoices, imports) where "the owner and nobody else" is the whole access model.

Vercel Blob

Apps already on Vercel that want user uploads (avatars, attachments, imports) without adding a cloud account, IAM, CORS rules or a second bill. Strongest when files are small to medium and read by their owner.

Trade-offsVerbatim from the manifestSupabase Storage
  • Egress is billed. If you serve large media at volume, the transfer line will outgrow the storage line. That is the case R2 exists for.
  • Policies are SQL against storage.objects, so the key layout is part of your security model. Change the shape of your keys and every policy changes with it.
  • The service role key bypasses every policy. Server code that uses it does its own authorisation, and the RLS policies only guard what holds a user token.
  • Image transformation is convenient and metered per origin image. Cheap for avatars, surprising for a gallery.
  • Signed upload URLs last two hours and that cannot be shortened, so treat the URL itself as a credential.
  • One bucket per access model, not per feature. Public and private objects in one bucket end in leaked files or a pile of policy exceptions.
Vercel Blob
  • Egress is billed. Blob data transfer is cheaper than Vercel's regular CDN transfer, but it is not zero. Large media served at volume is the case R2 exists for.
  • A store is private or public forever. You pick at creation and cannot change it. Mixing both means two stores.
  • Advanced operations are the expensive line. Every put, copy and list counts, and so does browsing the store in the Vercel dashboard.
  • Authorisation is your code. Blob has no row level security. The upload route decides who may write and where, every time.
  • onUploadCompleted is a webhook from Vercel to your app. It cannot reach localhost, so local testing needs a tunnel.
  • Overwrites and deletes take up to 60 seconds to leave the cache. Treat blobs as immutable and give every version a new pathname.
Required companionsAdded for you, with a reasonSupabase Storage
  • Supabase
Vercel Blob

Nothing. It stands on its own.

Recommended alongsideSuggested, never added for youSupabase Storage
  • An auth battery
Vercel Blob
  • An auth battery
Env vars you will manageEvery one documented in docs/onboard.mdSupabase Storage

3 variables · 1 required

  • SUPABASE_STORAGE_BUCKET
  • STORAGE_ALLOWED_ORIGINS
  • STORAGE_DEV_UPLOADER
Vercel Blob

4 variables · 1 required

  • BLOB_READ_WRITE_TOKEN
  • STORAGE_ALLOWED_ORIGINS
  • STORAGE_DEV_UPLOADER
  • VERCEL_BLOB_CALLBACK_URL
Dependencies addedSupabase Storage
  • @supabase/supabase-js ^2.117.0
  • server-only ^0.0.1
Vercel Blob
  • @vercel/blob ^2.8.0
  • server-only ^0.0.1
MCP serversWritten into .mcp.jsonSupabase Storage

None. No extra agent tools from this one.

Vercel Blob

None. No extra agent tools from this one.

Footprint in your repoSupabase Storage

12 files, plus 3 injections into shared stack files

Vercel Blob

13 files, plus 3 injections into shared stack files

What changes in your repo

The paths each battery contributes, diffed. A path in the third list is written by both, so swapping rewrites that file rather than adding one.

Only with Supabase Storage (2)

  • supabase/1 file
    • migrations/1 file
      • 20250101000200_storage_bucket.sql
  • variants/1 file
    • auth-supabase/1 file
      • supabase/1 file
        • migrations/1 file
          • 20250101000201_storage_policies.sql

Only with Vercel Blob (3)

  • src/2 files
    • lib/2 files
      • storage/2 files
        • access.ts
        • confirm.ts
  • variants/1 file
    • auth-clerk/1 file
      • slots/1 file
        • auth-public-routes.ts

Same path, different implementation (10)

  • src/5 files
    • app/1 file
      • api/1 file
        • upload/1 file
          • route.ts
    • components/1 file
      • upload/1 file
        • file-dropzone.tsx
    • lib/3 files
      • storage/3 files
        • authorize.ts
        • index.ts
        • keys.ts
  • tests/1 file
    • unit/1 file
      • storage-keys.test.ts
  • variants/4 files
    • auth-none/1 file
      • src/1 file
        • lib/1 file
          • storage/1 file
            • uploader.ts
    • auth-wired/1 file
      • src/1 file
        • lib/1 file
          • storage/1 file
            • uploader.ts
    • errors-none/1 file
      • src/1 file
        • lib/1 file
          • storage/1 file
            • report.ts
    • errors-sentry/1 file
      • src/1 file
        • lib/1 file
          • storage/1 file
            • report.ts

Shared stack files Supabase Storage injects into

  • env-required
  • legal-processors
  • verify-checks

Shared stack files Vercel Blob injects into

  • env-required
  • legal-processors
  • verify-checks

Supabase Storage in your .env.local

.env.localbash6 lines
# required
SUPABASE_STORAGE_BUCKET=uploads

# optional
STORAGE_ALLOWED_ORIGINS=https://app.example.com,https://staging.example.com
STORAGE_DEV_UPLOADER=dev-user

Vercel Blob in your .env.local

.env.localbash7 lines
# required
BLOB_READ_WRITE_TOKEN=vercel_blob_rw_0123456789abcdef_0123456789abcdef0123456789abcdef

# optional
STORAGE_ALLOWED_ORIGINS=https://app.example.com,https://staging.example.com
STORAGE_DEV_UPLOADER=dev-user
VERCEL_BLOB_CALLBACK_URL=

What changes for your agents

Each battery ships rules, skills, subagents and hooks that an agent loads before it touches the code that battery owns. Picking one is also picking how your agents behave in src/lib/storage/**.

Supabase Storage

  • 2

    Skills

  • 2

    Rules

  • 5

    Solution docs

Rules (2)

Buckets and their policies are migrations, not console clicks

supabase/migrations/** · src/lib/storage/**

Never sign a URL without an authorisation check, and never proxy uploads

src/lib/storage/** · src/app/api/upload/** · src/components/upload/**

Skills (2)

/add-bucket-policy

Add or change a Supabase Storage bucket and its row level security policies as a migration, then prove the policy actually denies what it should.

/upload-flow

Add a complete file upload to a feature: authorised signing route, direct-to-storage upload, the database row that records the key, and the cleanup that stops orphans.

Subagents and hooks

None of its own. The foundation agents and guard hooks still ship.

Vercel Blob

  • 2

    Skills

  • 2

    Rules

  • 7

    Solution docs

Rules (2)

Vercel Blob store - access mode, credentials, cache, cost

src/lib/storage/** · scripts/verify.ts

Client uploads - auth before the token, the server names the key, the token is locked down

src/lib/storage/** · src/app/api/upload/** · src/components/upload/**

Skills (2)

/add-upload-kind

Add a new kind of upload (avatars, attachments, imports) to the Vercel Blob flow, with its own folder, type and size limits, the row that owns the key, and the cleanup that stops orphans.

/clean-orphaned-blobs

Find and delete Vercel Blob objects no database row points at, safely, in batches, without deleting uploads that are still in flight.

Subagents and hooks

None of its own. The foundation agents and guard hooks still ship.

What each one already knows

Solution docs land in docs/solutions/ in your repo and are published here, so you can read the failure modes before you commit.

Supabase Storage (5)

Vercel Blob (7)

Which one to pick

From meta.bestFor and meta.tradeoffs. If a claim is not in the manifest, it is not on this page.

Pick Supabase Storage when

Teams already on Supabase who want files under the same policies as their rows. Same migrations, same pull request. Strongest for private per-user files (avatars, invoices, imports) where "the owner and nobody else" is the whole access model.

And accept that(6)
  • Egress is billed. If you serve large media at volume, the transfer line will outgrow the storage line. That is the case R2 exists for.
  • Policies are SQL against storage.objects, so the key layout is part of your security model. Change the shape of your keys and every policy changes with it.
  • The service role key bypasses every policy. Server code that uses it does its own authorisation, and the RLS policies only guard what holds a user token.
  • Image transformation is convenient and metered per origin image. Cheap for avatars, surprising for a gallery.
  • Signed upload URLs last two hours and that cannot be shortened, so treat the URL itself as a credential.
  • One bucket per access model, not per feature. Public and private objects in one bucket end in leaked files or a pile of policy exceptions.

Pick Vercel Blob when

Apps already on Vercel that want user uploads (avatars, attachments, imports) without adding a cloud account, IAM, CORS rules or a second bill. Strongest when files are small to medium and read by their owner.

And accept that(6)
  • Egress is billed. Blob data transfer is cheaper than Vercel's regular CDN transfer, but it is not zero. Large media served at volume is the case R2 exists for.
  • A store is private or public forever. You pick at creation and cannot change it. Mixing both means two stores.
  • Advanced operations are the expensive line. Every put, copy and list counts, and so does browsing the store in the Vercel dashboard.
  • Authorisation is your code. Blob has no row level security. The upload route decides who may write and where, every time.
  • onUploadCompleted is a webhook from Vercel to your app. It cannot reach localhost, so local testing needs a tunnel.
  • Overwrites and deletes take up to 60 seconds to leave the cache. Treat blobs as immutable and give every version a new pathname.

Questions people actually ask

Should I choose Supabase Storage or Vercel Blob?
Supabase Storage is best for teams already on Supabase who want files under the same policies as their rows. Same migrations, same pull request. Strongest for private per-user files (avatars, invoices, imports) where "the owner and nobody else" is the whole access model. Vercel Blob is best for apps already on Vercel that want user uploads (avatars, attachments, imports) without adding a cloud account, IAM, CORS rules or a second bill. Strongest when files are small to medium and read by their owner. Both fill the file storage slot, so a generated repo carries one or the other, never both.
How much do Supabase Storage and Vercel Blob cost?
Supabase Storage: Part of your Supabase plan. Free: 1 GB stored and 5 GB egress. Pro: 100 GB stored, then $0.0213/GB, and 250 GB egress, then $0.09/GB ($0.03/GB for cached egress). Image transformations need Pro: 100 origin images included, then $5 per 1,000. Vercel Blob: Hobby: free up to 1 GB stored, 10,000 simple and 2,000 advanced operations, and 10 GB of transfer a month. Past the limit, Blob stops until the 30 days reset. Pro bills by usage. Prices below are for iad1. Storage is $0.023 per GB-month and transfer $0.05 per GB. Simple operations (cache-miss reads) are $0.40 per million. Advanced operations (put, copy, list) are $5 per million. Deletes are free. Client uploads have no transfer charge.
What changes in my repo if I switch from Supabase Storage to Vercel Blob?
Supabase Storage writes 12 files, 3 environment variables and 2 dependencies, and installs 2 path-scoped rules, 2 skills and 5 solution docs. Vercel Blob writes 13 files, 4 environment variables and 2 dependencies, and installs 2 path-scoped rules, 2 skills and 7 solution docs.

Decide once, then build the repo that already knows the decision.

Either way you get that choice’s rules, skills and solution docs installed, plus the guard hooks, an onboarding doc for exactly these env vars, and the Compound Engineering loop. Free and MIT.