supabase-rb-rb
Storage

Create a bucket

Create a new storage bucket. Pick public (anonymous reads OK) or private (auth required).

Create a new bucket. The id you pass becomes the slug used in object URLs (e.g. /object/public/<id>/path/to/file.png), so prefer URL-safe lowercase identifiers.

The single most important decision on this call is the public: flag:

  • public: true — anonymous reads are allowed via the public URL. Writes still require auth. Use for avatars, marketing images, anything you'd serve from a CDN.
  • public: false (the default if omitted, treated as private by storage-api) — every read goes through a signed URL or an authenticated session. Use for private uploads, paywalled assets, anything that needs RLS.

You can flip public: later with update_bucket, but the bucket cannot be re-created with a different id without first emptying and deleting the old one.

Service-role key required

Bucket admin endpoints reject the publishable / anon key with 401 Unauthorized. Construct the client with the service-role JWT.

Signature

supabase.storage.create_bucket(id,name: nil,public: nil,file_size_limit: nil,allowed_mime_types: nil)

Parameters

NameTypeRequiredDescription
idStringRequiredBucket identifier. Becomes the slug used in public/signed URLs. Prefer URL-safe lowercase characters.
nameStringOptionalDisplay name. Defaults to id when omitted (the wire payload always carries name; storage-api uses id when name is missing).
publicBooleanOptionaltrue allows anonymous reads via the public URL. false (or omitted) keeps reads behind auth/signed URLs.
file_size_limitIntegerOptionalMaximum object size in bytes. Uploads exceeding this size are rejected. Omit (or pass nil) for unbounded.
allowed_mime_typesArray<String>OptionalAllowlist of object content types (e.g. ["image/png", "image/jpeg"]). Uploads with other content types are rejected. Omit for any.

Returns

Returns
Hash

The raw storage-api response body, typically { "name" => "<id>" } echoing the new bucket's id. The body is intentionally not wrapped in a Bucket struct — call get_bucket afterwards if you need the full record.

Example — public bucket (CDN-style)

supabase.storage.create_bucket("avatars", public: true)
# => { "name" => "avatars" }

# Anyone can now read /object/public/avatars/<file>.
supabase.storage.from("avatars").upload("ada.png", File.binread("ada.png"))
supabase.storage.from("avatars").get_public_url("ada.png")
# => "https://project.supabase.co/storage/v1/object/public/avatars/ada.png"

Example — private bucket with size + MIME guards

supabase.storage.create_bucket(
  "private-uploads",
  public: false,
  file_size_limit: 10 * 1024 * 1024,             # 10 MB
  allowed_mime_types: ["image/png", "image/jpeg", "application/pdf"]
)

# Reads now require an authenticated session or a signed URL.
supabase.storage.from("private-uploads").create_signed_url("contract.pdf", 60)

Example — minimal call

# Defaults to private, no size or MIME guard.
supabase.storage.create_bucket("scratch")

On this page