/storage/v1/* on your project URL. It manages files in buckets backed by S3, with object metadata mirrored into the storage.buckets and storage.objects tables in Postgres so RLS can gate access.
For the conceptual model, see Storage model. For uploading, see Storage uploads. For RLS, see Storage policies.
Common headers
Authorization is the pattern for browser-direct uploads. Service Role in both is for server-side admin operations.
The Storage API uses bearer auth for most endpoints. Public-URL reads (/object/public/*) work without auth; signed-URL reads pass auth via a ?token= query parameter.
Buckets
A bucket is a top-level container with a name, public flag, optional MIME allowlist, and optional file-size override.POST /storage/v1/bucket
Create a new bucket.string
required
Bucket id (used in URLs). Must be unique. Lowercase alphanumeric, dashes, and dots.
string
Human-readable name. Defaults to
id.boolean
When
true, the bucket’s public URL (/object/public/{bucket}/{path}) returns files without auth. Default false.integer
Per-bucket override for the project’s default file size limit. In bytes.
string[]
Restrict uploads to specific Content-Types. Default null = anything.
{ "name": "avatars" } on 200.
GET /storage/v1/bucket
List all buckets. Returns the bucket metadata rows fromstorage.buckets, filtered by SELECT policies.
{ id, name, public, owner, created_at, updated_at, file_size_limit, allowed_mime_types }.
GET /storage/v1/bucket/
Get a specific bucket’s metadata.PUT /storage/v1/bucket/
Update bucket metadata. Body fields are the same as create (public, file_size_limit, allowed_mime_types).
DELETE /storage/v1/bucket/
Delete an empty bucket. Returns409 not_empty if the bucket contains any objects; empty it first via POST /bucket/{id}/empty or DELETE the objects individually.
POST /storage/v1/bucket//empty
Delete all objects in a bucket without removing the bucket itself. Returns200 OK.
Objects
The core file operations. Object endpoints are routed by bucket + path.POST /storage/v1/object//
Upload a new file. The path can include slashes; they’re stored verbatim, not interpreted as folders by Storage. Returns409 Duplicate if a file already exists at that path; use PUT or set the x-upsert: true header to overwrite.
Headers:
Content-Type: the MIME type of the file. Checked against the bucket’sallowed_mime_typesif set.x-upsert: true(optional): overwrite if exists.
{ "Id": "...", "Key": "avatars/user-123/avatar.png" }.
PUT /storage/v1/object//
Overwrite an existing file at the same path. Same body shape as POST. Returns200 OK.
GET /storage/v1/object/public//
Fetch a file from a public bucket. No auth required. Returns the file bytes with the storedContent-Type. Returns 400 if the bucket is not public.
GET /storage/v1/object/authenticated//
Fetch a file from any bucket. RequiresAuthorization: Bearer <access token>. RLS on storage.objects decides whether the request succeeds.
DELETE /storage/v1/object//
Delete a single file. Requires DELETE policy match onstorage.objects for the calling role.
POST /storage/v1/object/list/
List files in a bucket. Filtered by SELECT policies onstorage.objects.
string
Only return files whose
name starts with this prefix.integer
Max files to return. Default 100.
integer
Pagination offset.
object
{ column: "name" | "created_at" | "updated_at", order: "asc" | "desc" }.string
Substring search on
name. Case-insensitive.{ id, name, bucket_id, owner, created_at, updated_at, last_accessed_at, metadata }.
POST /storage/v1/object/copy
Copy a file to a new location (potentially in a different bucket).string
required
Source bucket.
string
required
Source path.
string
Destination bucket. Defaults to source bucket.
string
required
Destination path.
POST /storage/v1/object/move
Move a file to a new location. Same parameters as copy; the source is deleted on success.Signed URLs
For sharing files via TTL-bounded URLs that work without auth.POST /storage/v1/object/sign//
Mint a download signed URL.integer
URL TTL in seconds. Default 60. Max 604800 (7 days).
{ "signedURL": "/object/sign/documents/report.pdf?token=..." }. The URL is path-relative; prepend your BASE_URL to get the full URL.
GET /storage/v1/object/sign//?token=…
Fetch a file via a signed URL. The token is the signature; no other auth required.POST /storage/v1/object/upload/sign//
Mint an upload signed URL: your server creates the URL, the client PUTs the file directly to it. Useful for high-bandwidth flows or offline clients.integer
URL TTL in seconds. Default 7200 (2 hours).
{ "url": "/object/upload/sign/documents/report.pdf?token=..." }. The client then PUTs to <BASE_URL>{url} with the file bytes and Content-Type header.
POST /storage/v1/object/sign
Sign multiple URLs in one request. Body:{ "paths": ["bucket1/path1", "bucket2/path2"], "expiresIn": 3600 }. Returns an array of signed URLs.
Image transformations
Therender/image endpoints route through imgproxy. The path shape mirrors the object endpoints (public, authenticated, sign) with the same auth requirements.
GET /storage/v1/render/image/public//
Fetch a transformed image from a public bucket. Pass transformations as query parameters.integer
Output width in pixels.
integer
Output height in pixels.
string
cover, contain, or fill. Default cover.integer
JPEG/WebP quality, 0-100. Default 80.
string
webp, png, jpeg, or origin. Default origin (preserves the original format).GET /storage/v1/render/image/authenticated//
Same as above but auth-gated.GET /storage/v1/render/image/sign//?token=…
Same as above via signed URL. To mint a signed transformation URL, hitPOST /storage/v1/object/sign/{bucket}/{path} with a transform parameter in the body:
TUS resumable uploads
For files larger than 50MB (the per-request limit). Implements the TUS 1.0 protocol. Use a TUS client library rather than hand-rolling.POST /storage/v1/upload/resumable
Initiate a resumable upload. SubsequentPATCH requests with Upload-Offset headers stream the chunks. HEAD requests query progress.
Required headers:
apikeyAuthorization: Bearer <token>Upload-Length: <total bytes>Upload-Metadata: bucketName <base64>,objectName <base64>,contentType <base64>Tus-Resumable: 1.0.0
tus-js-client.
Error responses
Storage returns errors as{"statusCode": "<code>", "error": "<machine-readable>", "message": "<human-readable>"}. Common cases:
Next steps
Storage uploads
The four upload flows with worked examples.
Storage policies
RLS patterns on storage.objects.
Storage model
Buckets, public vs private, the underlying tables.
Auth Reference
The auth surface that mints the tokens you’ll use here.