backend

Supabase Storage Rest Api: Endpoints And Examples

Working with file uploads usually means wrestling with bulky SDKs or complex cloud provider permissions. If your stack doesn't support an official Supabase client library, or if you prefer direct HTTP

Supabase Storage Rest Api: Endpoints And Examples
In this story

Working with file uploads usually means wrestling with bulky SDKs or complex cloud provider permissions. If your stack doesn't support an official Supabase client library, or if you prefer direct HTTP requests, you can interact with Supabase Storage directly through its underlying HTTP endpoints.

Supabase exposes a dedicated storage API layer running on top of Postgres. You can manage buckets, upload files, download assets, and enforce security policies using plain HTTP requests. This guide breaks down how to configure your headers, structure your endpoints, and execute core file operations without relying on heavier wrapper libraries.

Understanding the Supabase Storage Architecture

Before sending requests, it helps to know how Supabase structures its storage layer. Every project gets a unique API URL formatted as https://<PROJECT_REF>.supabase.co. The storage service lives under the /storage/v1 path namespace.

Unlike the database REST API (powered by PostgREST), the storage service uses its own specialized endpoints for handling binary data, multi-part form uploads, and asset transformations.

You need two primary pieces of authentication information from your Supabase dashboard:

  • Project URL: Found under your project settings, pointing to your specific tenant.
  • API Keys: The anon key for public operations governed by Row Level Security (RLS), or the service_role key for administrative backend tasks that bypass restrictions.

Every request must include specific authorization headers. Let's look at the standard header configuration required for all operations:

Authorization: Bearer YOUR_SUPABASE_ANON_OR_SERVICE_KEY
ApiKey: YOUR_SUPABASE_ANON_OR_SERVICE_KEY

Omitting either the Authorization or ApiKey header will result in a 401 Unauthorized response, even if your bucket is set to public.

Managing Buckets via HTTP

Buckets act as containers for your files. While you can create them easily in the dashboard, automating bucket creation or checking existing buckets via the REST API is useful for deployment scripts and multi-tenant systems.

Creating a New Bucket

To create a bucket, send a POST request to the /storage/v1/bucket endpoint. You'll pass a JSON payload defining the bucket name and its public visibility status.

POST /storage/v1/bucket HTTP/1.1
Host: YOUR_PROJECT_REF.supabase.co
Authorization: Bearer YOUR_SERVICE_ROLE_KEY
ApiKey: YOUR_SERVICE_ROLE_KEY
Content-Type: application/json

{
  "id": "documents",
  "name": "documents",
  "public": false
}

If successful, the API returns a 200 OK status with the bucket details. Setting public to false ensures that files inside require authenticated URLs or signed tokens to download.

Listing All Buckets

To retrieve an inventory of your existing buckets, execute a GET request on the bucket collection endpoint:

GET /storage/v1/bucket HTTP/1.1
Host: YOUR_PROJECT_REF.supabase.co
Authorization: Bearer YOUR_SERVICE_ROLE_KEY
ApiKey: YOUR_SERVICE_ROLE_KEY

This returns an array of JSON objects detailing each bucket's ID, creation date, owner, and public configuration flag.

Uploading Files with the REST API

Uploading files requires sending binary data or multi-part form data to the object endpoints. The endpoint structure depends on whether you are creating a new file or updating an existing one.

Performing a Standard File Upload

To upload a file into a specific bucket, use a POST or PUT request targeting /storage/v1/object/{bucket_name}/{file_path}.

Here is an example using cURL to upload a PDF file named report.pdf into the documents bucket:

curl -X POST "https://YOUR_PROJECT_REF.supabase.co/storage/v1/object/documents/reports/report.pdf" \
  -H "Authorization: Bearer YOUR_SUPABASE_ANON_KEY" \
  -H "ApiKey: YOUR_SUPABASE_ANON_KEY" \
  -H "Content-Type: application/pdf" \
  --data-binary "@path/to/local/report.pdf"
  • Bucket Name: Placed directly in the URI path after /object/.
  • File Path: Includes any virtual folder hierarchy, such as reports/report.pdf. Supabase automatically generates missing virtual folders.
  • Content-Type: Must match the actual MIME type of the file you're uploading.

If you attempt to upload a file to a path that already exists using a POST request, the API will throw a conflict error unless you use a PUT request to overwrite it.

Downloading and Accessing Files

Retrieving files depends entirely on whether your bucket is configured as public or private.

Fetching Files from Public Buckets

If your bucket is public, files have a permanent public URL that you can access directly without headers or authorization tokens. The public URL structure looks like this:

https://YOUR_PROJECT_REF.supabase.co/storage/v1/object/public/documents/reports/report.pdf

You can drop this URL straight into an img tag, an iframe, or an anchor link in your frontend application.

Fetching Files from Private Buckets

For private buckets, direct URLs return access denied errors. Instead, you must request a signed URL that expires after a set duration, or download the file binary directly through an authenticated API call.

To generate a short-lived signed URL via the REST API, send a POST request to the sign endpoint:

POST /storage/v1/object/sign/documents/reports/report.pdf HTTP/1.1
Host: YOUR_PROJECT_REF.supabase.co
Authorization: Bearer YOUR_SERVICE_ROLE_KEY
ApiKey: YOUR_SERVICE_ROLE_KEY
Content-Type: application/json

{
  "expiresIn": 60
}

The response returns a signed URL containing a token valid for the specified number of seconds (in this case, 60 seconds), allowing secure, temporary access to private assets. You can learn more about securing endpoints through the official Supabase API Documentation.

Deleting Files

Removing files via HTTP is straightforward. Send a DELETE request to the object endpoint with the target file path.

DELETE /storage/v1/object/documents/reports/report.pdf HTTP/1.1
Host: YOUR_PROJECT_REF.supabase.co
Authorization: Bearer YOUR_SUPABASE_ROLE_KEY
ApiKey: YOUR_SUPABASE_ROLE_KEY

You can also delete multiple files at once by sending a POST request to /storage/v1/object/documents with a JSON payload containing an array of paths to purge.

Common Integration Pitfalls

Building custom HTTP wrappers for file storage often introduces subtle bugs. Watch out for these frequent missteps:

  • Missing Content-Type headers: If you omit or mislabel the Content-Type, Supabase may store the file as an arbitrary octet-stream, breaking browser rendering.
  • Incorrect URL formatting: Forgetting the object segment in your URI path (e.g., writing /storage/v1/documents/... instead of /storage/v1/object/documents/...) results in 404 errors.
  • RLS policy blocks: If your inserts fail with a 403 Forbidden status despite correct keys, check your database storage policies. Row Level Security policies dictate who can write to specific buckets. You can reference the Supabase Storage Quickstart Guide for setting up proper object policies.

Frequently Asked Questions

Can I upload files larger than 50MB using the REST API?

Yes, but for large files, standard HTTP requests can time out. For large assets, you should implement resumable uploads using the TUS protocol endpoints provided under /storage/v1/upload/resumable.

How do I apply image transformations via the REST API?

Supabase supports on-the-fly image resizing and optimization. You can retrieve transformed images by hitting the render endpoint instead of the standard object endpoint:

https://YOUR_PROJECT_REF.supabase.co/storage/v1/render/image/public/bucket/image.png?width=300&height=200

What is the difference between the anon key and service role key in storage requests?

The anon key respects Row Level Security (RLS) policies, meaning users can only access or modify files they own or have explicit permission to see. The service_role key bypasses all RLS rules and should only be used in secure server-side environments.

Why am I getting a CORS error when calling the storage REST API from a browser?

CORS errors occur when your browser origin isn't allowed by your Supabase project settings, or when you fail to include the required ApiKey header alongside your Authorization header.

IC

Written by

Isabella Carter

As a veteran correspondent, Isabella Carter has reported from across the globe, bringing firsthand perspectives to international stories and local issues.

More from backend