Build the package
<br /> <p align="center"> <a href="https://supabase.io"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg"> <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo
Overview
Requirements
- Node.js 20 or later (Node.js 18 support dropped as of October 31, 2025)
- For browser support, all modern browsers are supported
⚠️ Node.js 18 Deprecation Notice
Node.js 18 reached end-of-life on April 30, 2025. As announced in our deprecation notice, support for Node.js 18 was dropped on October 31, 2025.
Features
- File Storage: Upload, download, list, move, and delete files
- Access Control: Public and private buckets with fine-grained permissions
- Signed URLs: Generate time-limited URLs for secure file access
- Image Transformations: On-the-fly image resizing and optimization
- Vector Embeddings: Store and query high-dimensional embeddings with similarity search
- Analytics Buckets: Iceberg table-based buckets optimized for analytical queries and data processing
Quick Start Guide
Installing the module
npm install @supabase/storage-js
Connecting to the storage backend
There are two ways to use the Storage SDK:
Option 1: Via Supabase Client (Recommended)
If you're already using @supabase/supabase-js, access storage through the client:
// Use publishable/anon key for frontend applications
const supabase = createClient('https://<project_ref>.supabase.co', '<your-publishable-key>')
// Access storage
const storage = supabase.storage
// Access different bucket types
const regularBucket = storage.from('my-bucket')
const vectorBucket = storage.vectors.from('embeddings-bucket')
const analyticsBucket = storage.analytics // Analytics API
Option 2: Standalone StorageClient
For backend applications or when you need to bypass Row Level Security:
const STORAGE_URL = 'https://<project_ref>.supabase.co/storage/v1'
const SERVICE_KEY = '<your-secret-key>' // Use secret key for backend operations
const storageClient = new StorageClient(STORAGE_URL, {
apikey: SERVICE_KEY,
Authorization: `Bearer ${SERVICE_KEY}`,
})
// Access different bucket types
const regularBucket = storageClient.from('my-bucket')
const vectorBucket = storageClient.vectors.from('embeddings-bucket')
const analyticsBucket = storageClient.analytics // Analytics API
When to use each approach:
- Use
supabase.storagewhen working with other Supabase features (auth, database, etc.) in frontend applications- Use
new StorageClient()for backend applications, Edge Functions, or when you need to bypass RLS policies
Note: Refer to the Storage Access Control guide for detailed information on creating RLS policies.
Understanding Bucket Types
Supabase Storage supports three types of buckets, each optimized for different use cases:
1. Regular Storage Buckets (File Storage)
Standard buckets for storing files, images, videos, and other assets.
// Create regular storage bucket
const { data, error } = await storageClient.createBucket('my-files', {
public: false,
})
// Upload files
await storageClient.from('my-files').upload('avatar.png', file)
Use cases: User uploads, media assets, documents, backups
2. Vector Buckets (Embeddings Storage)
Specialized buckets for storing and querying high-dimensional vector embeddings.
// Create vector bucket
await storageClient.vectors.createBucket('embeddings-prod')
// Create index and insert vectors
const bucket = storageClient.vectors.from('embeddings-prod')
await bucket.createIndex({
indexName: 'documents',
dimension: 1536,
distanceMetric: 'cosine',
})
Use cases: Semantic search, AI-powered recommendations, similarity matching
See full Vector Embeddings documentation below
3. Analytics Buckets
Specialized buckets using Apache Iceberg table format, optimized for analytical queries and large-scale data processing.
// Create analytics bucket
await storageClient.analytics.createBucket('analytics-data')
// List analytics buckets
const { data, error } = await storageClient.analytics.listBuckets()
// Delete analytics bucket
await storageClient.analytics.deleteBucket('analytics-data')
Use cases: Time-series data, analytical queries, data lakes, large-scale data processing, business intelligence
See full Analytics Buckets documentation below
Handling resources
Handling Storage Buckets
-
Create a new Storage bucket:
const { data, error } = await storageClient.createBucket( 'test_bucket', // Bucket name (must be unique) { public: false } // Bucket options ) -
Retrieve the details of an existing Storage bucket:
const { data, error } = await storageClient.getBucket('test_bucket') -
Update a new Storage bucket:
const { data, error } = await storageClient.updateBucket( 'test_bucket', // Bucket name { public: false } // Bucket options ) -
Remove all objects inside a single bucket:
const { data, error } = await storageClient.emptyBucket('test_bucket') -
Delete an existing bucket (a bucket can't be deleted with existing objects inside it):
const { data, error } = await storageClient.deleteBucket('test_bucket') -
Retrieve the details of all Storage buckets within an existing project:
// List all buckets const { data, error } = await storageClient.listBuckets() // List buckets with options (pagination, sorting, search) const { data, error } = await storageClient.listBuckets({ limit: 10, offset: 0, sortColumn: 'created_at', sortOrder: 'desc', search: 'prod', })
Handling Files
-
Upload a file to an existing bucket:
const fileBody = ... // load your file here const { data, error } = await storageClient.from('bucket').upload('path/to/file', fileBody)Note:
The path indata.Keyis prefixed by the bucket ID and is not the value which should be passed to thedownloadmethod in order to fetch the file.
To fetch the file via thedownloadmethod, usedata.pathanddata.bucketIdas follows:const { data, error } = await storageClient.from('bucket').upload('/folder/file.txt', fileBody) // check for errors const { data2, error2 } = await storageClient.from(data.bucketId).download(data.path)Note: The
uploadmethod also accepts a map of optional parameters. For a complete list see the Supabase API reference. -
Download a file from an exisiting bucket:
const { data, error } = await storageClient.from('bucket').download('path/to/file') -
List all the files within a bucket:
const { data, error } = await storageClient.from('bucket').list('folder')Note: The
listmethod also accepts a map of optional parameters. For a complete list see the Supabase API reference. -
Replace an existing file at the specified path with a new one:
const fileBody = ... // load your file here const { data, error } = await storageClient .from('bucket') .update('path/to/file', fileBody)Note: The
uploadmethod also accepts a map of optional parameters. For a complete list see the Supabase API reference. -
Move an existing file:
const { data, error } = await storageClient .from('bucket') .move('old/path/to/file', 'new/path/to/file') -
Delete files within the same bucket:
const { data, error } = await storageClient.from('bucket').remove(['path/to/file']) -
Create signed URL to download file without requiring permissions:
const expireIn = 60 const { data, error } = await storageClient .from('bucket') .createSignedUrl('path/to/file', expireIn) -
Retrieve URLs for assets in public buckets:
const { data, error } = await storageClient.from('public-bucket').getPublicUrl('path/to/file')
Analytics Buckets
Supabase Storage provides specialized analytics buckets using Apache Iceberg table format, optimized for analytical workloads and large-scale data processing. These buckets are designed for data lake architectures, time-series data, and business intelligence applications.
What are Analytics Buckets?
Analytics buckets use the Apache Iceberg open table format, providing:
- ACID transactions for data consistency
- Schema evolution without data rewrites
- Time travel to query historical data
- Efficient metadata management for large datasets
- Optimized for analytical queries rather than individual file operations
When to Use Analytics Buckets
Use analytics buckets for:
- Time-series data (logs, metrics, events)
- Data lake architectures
- Business intelligence and reporting
- Large-scale batch processing
- Analytical workloads requiring ACID guarantees
Use regular storage buckets for:
- User file uploads (images, documents, videos)
- Individual file management
- Content delivery
- Simple object storage needs
Quick Start
You can access analytics functionality through the analytics property on your storage client:
Via Supabase Client
const supabase = createClient('https://your-project.supabase.co', 'your-publishable-key')
// Access analytics operations
const analytics = supabase.storage.analytics
// Create an analytics bucket
const { data, error } = await analytics.createBucket('analytics-data')
if (error) {
console.error('Failed to create analytics bucket:', error.message)
} else {
console.log('Created bucket:', data.name)
}
Via StorageClient
const storageClient = new StorageClient('https://your-project.supabase.co/storage/v1', {
apikey: 'YOUR_API_KEY',
Authorization: 'Bearer YOUR_TOKEN',
})
// Access analytics operations
const analytics = storageClient.analytics
// Create an analytics bucket
await analytics.createBucket('analytics-data')
API Reference
Create Analytics Bucket
Creates a new analytics bucket using Iceberg table format:
const { data, error } = await analytics.createBucket('my-analytics-bucket')
if (error) {
console.error('Error:', error.message)
} else {
console.log('Created bucket:', data)
}
Returns:
{
data: {
id: string
type: 'ANALYTICS'
format: string
created_at: string
updated_at: string
} | null
error: StorageError | null
}
List Analytics Buckets
Retrieves all analytics buckets in your project with optional filtering and pagination:
const { data, error } = await analytics.listBuckets({
limit: 10,
offset: 0,
sortColumn: 'created_at',
sortOrder: 'desc',
search: 'prod',
})
if (data) {
console.log(`Found ${data.length} analytics buckets`)
data.forEach((bucket) => {
console.log(`- ${bucket.id} (created: ${bucket.created_at})`)
})
}
Parameters:
limit?: number- Maximum number of buckets to returnoffset?: number- Number of buckets to skip (for pagination)sortColumn?: 'id' | 'name' | 'created_at' | 'updated_at'- Column to sort bysortOrder?: 'asc' | 'desc'- Sort directionsearch?: string- Search term to filter bucket names
Returns:
{
data: AnalyticBucket[] | null
error: StorageError | null
}
Example with Pagination:
// Fetch first page
const firstPage = await analytics.listBuckets({
limit: 100,
offset: 0,
sortColumn: 'created_at',
sortOrder: 'desc',
})
// Fetch second page
const secondPage = await analytics.listBuckets({
limit: 100,
offset: 100,
sortColumn: 'created_at',
sortOrder: 'desc',
})
Delete Analytics Bucket
Deletes an analytics bucket. The bucket must be empty before deletion.
const { data, error } = await analytics.deleteBucket('old-analytics-bucket')
if (error) {
console.error('Failed to delete:', error.message)
} else {
console.log('Bucket deleted:', data.message)
}
Returns:
{
data: { message: string } | null
error: StorageError | null
}
Note: A bucket cannot be deleted if it contains data. You must empty the bucket first.
Get Iceberg Catalog for Advanced Operations
For advanced operations like creating tables, namespaces, and querying Iceberg metadata, use the from() method to get a configured iceberg-js client:
// Get an Iceberg REST Catalog client for your analytics bucket
const catalog = analytics.from('analytics-data')
// Create a namespace
await catalog.createNamespace({ namespace: ['default'] }, { properties: { owner: 'data-team' } })
// Create a table with schema
await catalog.createTable(
{ namespace: ['default'] },
{
name: 'events',
schema: {
type: 'struct',
fields: [
{ id: 1, name: 'id', type: 'long', required: true },
{ id: 2, name: 'timestamp', type: 'timest