0
# File Storage
1
2
File upload, download, and management system with access policies, image transformations, and CDN integration. Supports any file type with configurable permissions and automatic optimization for images.
3
4
## Capabilities
5
6
### Bucket Management
7
8
Organize files into buckets with different access policies and configurations.
9
10
```typescript { .api }
11
/**
12
* Retrieves the details of all Storage buckets within an existing project
13
* @returns Promise resolving to list of buckets or error
14
*/
15
listBuckets(): Promise<{
16
data: Bucket[] | null;
17
error: StorageError | null;
18
}>;
19
20
/**
21
* Creates a new Storage bucket
22
* @param id - A unique identifier for the bucket
23
* @param options - Bucket configuration options
24
* @returns Promise resolving to created bucket or error
25
*/
26
createBucket(id: string, options?: BucketOptions): Promise<{
27
data: Bucket | null;
28
error: StorageError | null;
29
}>;
30
31
/**
32
* Retrieves the details of an existing Storage bucket
33
* @param id - The unique identifier of the bucket
34
* @returns Promise resolving to bucket details or error
35
*/
36
getBucket(id: string): Promise<{
37
data: Bucket | null;
38
error: StorageError | null;
39
}>;
40
41
/**
42
* Updates a Storage bucket
43
* @param id - The unique identifier of the bucket
44
* @param options - Updated bucket configuration
45
* @returns Promise resolving to success message or error
46
*/
47
updateBucket(id: string, options: BucketOptions): Promise<{
48
data: { message: string } | null;
49
error: StorageError | null;
50
}>;
51
52
/**
53
* Removes all objects inside a single bucket
54
* @param id - The unique identifier of the bucket to empty
55
* @returns Promise resolving to success message or error
56
*/
57
emptyBucket(id: string): Promise<{
58
data: { message: string } | null;
59
error: StorageError | null;
60
}>;
61
62
/**
63
* Deletes an existing bucket
64
* @param id - The unique identifier of the bucket to delete
65
* @returns Promise resolving to success message or error
66
*/
67
deleteBucket(id: string): Promise<{
68
data: { message: string } | null;
69
error: StorageError | null;
70
}>;
71
72
interface Bucket {
73
id: string;
74
name: string;
75
owner: string;
76
public: boolean;
77
file_size_limit?: number;
78
allowed_mime_types?: string[];
79
created_at: string;
80
updated_at: string;
81
}
82
83
interface BucketOptions {
84
/** Whether the bucket is publicly accessible */
85
public?: boolean;
86
/** The maximum file size allowed (in bytes) */
87
fileSizeLimit?: number;
88
/** Allowed MIME types for uploads */
89
allowedMimeTypes?: string[];
90
}
91
```
92
93
**Usage Examples:**
94
95
```typescript
96
// List all buckets
97
const { data: buckets, error } = await supabase.storage.listBuckets();
98
if (buckets) {
99
console.log('Available buckets:', buckets);
100
}
101
102
// Create a new bucket
103
const { data, error } = await supabase.storage.createBucket('avatars', {
104
public: true,
105
fileSizeLimit: 1024 * 1024 * 2, // 2MB
106
allowedMimeTypes: ['image/png', 'image/jpeg', 'image/gif']
107
});
108
109
// Get bucket details
110
const { data: bucket, error } = await supabase.storage.getBucket('avatars');
111
112
// Update bucket settings
113
const { data, error } = await supabase.storage.updateBucket('avatars', {
114
public: false,
115
fileSizeLimit: 1024 * 1024 * 5 // 5MB
116
});
117
118
// Delete bucket
119
const { data, error } = await supabase.storage.deleteBucket('old-bucket');
120
```
121
122
### File Operations
123
124
Upload, download, list, and delete files within storage buckets.
125
126
```typescript { .api }
127
/**
128
* Get a reference to a FileApi instance for a specific bucket
129
* @param bucketId - The bucket identifier
130
* @returns FileApi instance for file operations
131
*/
132
from(bucketId: string): FileApi;
133
134
interface FileApi {
135
/**
136
* Uploads a file to an existing bucket
137
* @param path - The relative file path including filename
138
* @param fileBody - The file content (File, ArrayBuffer, or string)
139
* @param options - Upload options
140
* @returns Promise resolving to uploaded file object or error
141
*/
142
upload(
143
path: string,
144
fileBody: File | ArrayBuffer | string | Blob | FormData,
145
options?: FileOptions
146
): Promise<{
147
data: FileObject | null;
148
error: StorageError | null;
149
}>;
150
151
/**
152
* Downloads a file from the bucket
153
* @param path - The full path and filename of the file
154
* @param options - Download options
155
* @returns Promise resolving to file blob or error
156
*/
157
download(path: string, options?: TransformOptions): Promise<{
158
data: Blob | null;
159
error: StorageError | null;
160
}>;
161
162
/**
163
* Lists all files in a bucket or folder
164
* @param path - The folder path (optional, defaults to root)
165
* @param options - Search and pagination options
166
* @returns Promise resolving to file list or error
167
*/
168
list(path?: string, options?: SearchOptions): Promise<{
169
data: FileObject[] | null;
170
error: StorageError | null;
171
}>;
172
173
/**
174
* Removes files within the same bucket
175
* @param paths - Array of file paths to remove
176
* @returns Promise resolving to removed file objects or error
177
*/
178
remove(paths: string[]): Promise<{
179
data: FileObject[] | null;
180
error: StorageError | null;
181
}>;
182
183
/**
184
* Moves files within the same bucket
185
* @param fromPath - The original file path
186
* @param toPath - The new file path
187
* @returns Promise resolving to success message or error
188
*/
189
move(fromPath: string, toPath: string): Promise<{
190
data: { message: string } | null;
191
error: StorageError | null;
192
}>;
193
194
/**
195
* Copies files within the same bucket
196
* @param fromPath - The original file path
197
* @param toPath - The new file path
198
* @returns Promise resolving to success message or error
199
*/
200
copy(fromPath: string, toPath: string): Promise<{
201
data: { message: string } | null;
202
error: StorageError | null;
203
}>;
204
205
/**
206
* Create a signed URL for file access
207
* @param path - The file path
208
* @param expiresIn - URL expiration time in seconds
209
* @param options - Additional options for the signed URL
210
* @returns Promise resolving to signed URL or error
211
*/
212
createSignedUrl(path: string, expiresIn: number, options?: CreateSignedUrlOptions): Promise<{
213
data: { signedUrl: string } | null;
214
error: StorageError | null;
215
}>;
216
217
/**
218
* Create signed URLs for multiple files
219
* @param paths - Array of file paths
220
* @param expiresIn - URL expiration time in seconds
221
* @param options - Additional options for the signed URLs
222
* @returns Promise resolving to array of signed URLs or error
223
*/
224
createSignedUrls(paths: string[], expiresIn: number, options?: CreateSignedUrlOptions): Promise<{
225
data: SignedUrlResponse[] | null;
226
error: StorageError | null;
227
}>;
228
229
/**
230
* Get the public URL for a file (bucket must be public)
231
* @param path - The file path
232
* @param options - Transform options for images
233
* @returns Public URL data
234
*/
235
getPublicUrl(path: string, options?: PublicUrlOptions): {
236
data: { publicUrl: string };
237
};
238
239
/**
240
* Updates a file in the bucket
241
* @param path - The relative file path
242
* @param fileBody - The new file content
243
* @param options - Update options
244
* @returns Promise resolving to updated file object or error
245
*/
246
update(
247
path: string,
248
fileBody: File | ArrayBuffer | string | Blob | FormData,
249
options?: FileOptions
250
): Promise<{
251
data: FileObject | null;
252
error: StorageError | null;
253
}>;
254
}
255
256
interface FileObject {
257
name: string;
258
id?: string;
259
updated_at?: string;
260
created_at?: string;
261
last_accessed_at?: string;
262
metadata?: Record<string, any>;
263
buckets?: Bucket[];
264
}
265
266
interface FileOptions {
267
/** Cache control header */
268
cacheControl?: string;
269
/** Content type header */
270
contentType?: string;
271
/** Whether to upsert (overwrite existing file) */
272
upsert?: boolean;
273
/** Custom metadata */
274
metadata?: Record<string, string>;
275
}
276
277
interface SearchOptions {
278
/** The number of files to retrieve */
279
limit?: number;
280
/** The starting position */
281
offset?: number;
282
/** Sort by column */
283
sortBy?: { column: string; order: 'asc' | 'desc' };
284
/** Search query */
285
search?: string;
286
}
287
288
interface TransformOptions {
289
/** Image transformation options */
290
transform?: {
291
/** Resize width */
292
width?: number;
293
/** Resize height */
294
height?: number;
295
/** Resize mode */
296
resize?: 'cover' | 'contain' | 'fill';
297
/** Output format */
298
format?: 'origin' | 'webp';
299
/** Image quality (1-100) */
300
quality?: number;
301
};
302
}
303
304
interface CreateSignedUrlOptions {
305
/** Transform options for images */
306
transform?: TransformOptions['transform'];
307
/** Download file instead of displaying */
308
download?: boolean | string;
309
}
310
311
interface PublicUrlOptions {
312
/** Transform options for images */
313
transform?: TransformOptions['transform'];
314
/** Download file instead of displaying */
315
download?: boolean | string;
316
}
317
318
interface SignedUrlResponse {
319
error: string | null;
320
path: string;
321
signedUrl: string;
322
}
323
324
class StorageError extends Error {
325
statusCode?: string;
326
}
327
```
328
329
**Usage Examples:**
330
331
```typescript
332
// Upload a file
333
const file = event.target.files[0];
334
const { data, error } = await supabase.storage
335
.from('avatars')
336
.upload(`public/${file.name}`, file, {
337
cacheControl: '3600',
338
upsert: false
339
});
340
341
// Upload with custom filename
342
const { data, error } = await supabase.storage
343
.from('documents')
344
.upload(`user-123/document-${Date.now()}.pdf`, file, {
345
contentType: 'application/pdf',
346
metadata: {
347
owner: 'user-123',
348
category: 'legal'
349
}
350
});
351
352
// Download a file
353
const { data, error } = await supabase.storage
354
.from('avatars')
355
.download('public/avatar.jpg');
356
357
if (data) {
358
// Create a URL for the blob
359
const url = URL.createObjectURL(data);
360
// Use the URL in an image tag or download link
361
}
362
363
// Download with image transformations
364
const { data, error } = await supabase.storage
365
.from('images')
366
.download('photo.jpg', {
367
transform: {
368
width: 300,
369
height: 300,
370
resize: 'cover',
371
quality: 80
372
}
373
});
374
375
// List files in a bucket
376
const { data: files, error } = await supabase.storage
377
.from('documents')
378
.list('user-123/', {
379
limit: 100,
380
offset: 0,
381
sortBy: { column: 'name', order: 'asc' }
382
});
383
384
// Search for files
385
const { data: files, error } = await supabase.storage
386
.from('documents')
387
.list('user-123/', {
388
search: 'invoice'
389
});
390
391
// Remove files
392
const { data, error } = await supabase.storage
393
.from('avatars')
394
.remove(['public/avatar1.png', 'public/avatar2.png']);
395
396
// Move a file
397
const { data, error } = await supabase.storage
398
.from('documents')
399
.move('public/old-name.pdf', 'public/new-name.pdf');
400
401
// Copy a file
402
const { data, error } = await supabase.storage
403
.from('documents')
404
.copy('templates/invoice.pdf', 'user-123/invoice-copy.pdf');
405
```
406
407
### URL Generation
408
409
Generate public URLs and signed URLs for secure file access.
410
411
```typescript
412
// Get public URL (for public buckets)
413
const { data } = supabase.storage
414
.from('avatars')
415
.getPublicUrl('public/avatar.jpg');
416
417
console.log('Public URL:', data.publicUrl);
418
419
// Get public URL with transformations
420
const { data } = supabase.storage
421
.from('images')
422
.getPublicUrl('photo.jpg', {
423
transform: {
424
width: 500,
425
height: 300,
426
resize: 'cover',
427
format: 'webp',
428
quality: 85
429
}
430
});
431
432
// Create signed URL for private files
433
const { data, error } = await supabase.storage
434
.from('private-documents')
435
.createSignedUrl('user-123/confidential.pdf', 3600); // 1 hour expiry
436
437
if (data) {
438
console.log('Signed URL:', data.signedUrl);
439
}
440
441
// Create signed URL with download option
442
const { data, error } = await supabase.storage
443
.from('documents')
444
.createSignedUrl('report.pdf', 3600, {
445
download: 'monthly-report.pdf'
446
});
447
448
// Create multiple signed URLs
449
const { data, error } = await supabase.storage
450
.from('gallery')
451
.createSignedUrls(['image1.jpg', 'image2.jpg', 'image3.jpg'], 7200);
452
453
if (data) {
454
data.forEach((item, index) => {
455
if (!item.error) {
456
console.log(`URL ${index + 1}:`, item.signedUrl);
457
}
458
});
459
}
460
```
461
462
## Advanced Storage Patterns
463
464
### File Upload with Progress Tracking
465
466
```typescript
467
// Upload with progress tracking (requires additional implementation)
468
const uploadFileWithProgress = async (file: File, path: string) => {
469
const { data, error } = await supabase.storage
470
.from('uploads')
471
.upload(path, file, {
472
cacheControl: '3600',
473
upsert: false
474
});
475
476
if (error) {
477
console.error('Upload error:', error.message);
478
return null;
479
}
480
481
return data;
482
};
483
484
// For progress tracking, you might need to implement chunked uploads
485
// or use a third-party library that wraps the Supabase upload
486
```
487
488
### Image Processing Pipeline
489
490
```typescript
491
// Upload original image
492
const originalFile = event.target.files[0];
493
const timestamp = Date.now();
494
const originalPath = `originals/${timestamp}-${originalFile.name}`;
495
496
const { data: originalUpload, error: uploadError } = await supabase.storage
497
.from('images')
498
.upload(originalPath, originalFile);
499
500
if (!uploadError && originalUpload) {
501
// Generate different sizes using public URLs with transformations
502
const sizes = [
503
{ name: 'thumbnail', width: 150, height: 150 },
504
{ name: 'medium', width: 500, height: 500 },
505
{ name: 'large', width: 1200, height: 1200 }
506
];
507
508
const processedUrls = sizes.map(size => ({
509
...size,
510
url: supabase.storage
511
.from('images')
512
.getPublicUrl(originalPath, {
513
transform: {
514
width: size.width,
515
height: size.height,
516
resize: 'cover',
517
format: 'webp',
518
quality: 80
519
}
520
}).data.publicUrl
521
}));
522
523
console.log('Processed image URLs:', processedUrls);
524
}
525
```
526
527
### Batch File Operations
528
529
```typescript
530
// Upload multiple files
531
const uploadMultipleFiles = async (files: FileList, folder: string) => {
532
const uploads = Array.from(files).map(async (file, index) => {
533
const path = `${folder}/${Date.now()}-${index}-${file.name}`;
534
return supabase.storage
535
.from('uploads')
536
.upload(path, file, {
537
cacheControl: '3600'
538
});
539
});
540
541
const results = await Promise.all(uploads);
542
543
const successful = results.filter(result => !result.error);
544
const failed = results.filter(result => result.error);
545
546
console.log(`Uploaded ${successful.length} files successfully`);
547
if (failed.length > 0) {
548
console.error(`Failed to upload ${failed.length} files`);
549
}
550
551
return { successful, failed };
552
};
553
554
// Clean up old files
555
const cleanupOldFiles = async (bucketId: string, olderThanDays: number) => {
556
const cutoffDate = new Date();
557
cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);
558
559
const { data: files, error } = await supabase.storage
560
.from(bucketId)
561
.list('', { limit: 1000 });
562
563
if (error || !files) {
564
console.error('Error listing files:', error);
565
return;
566
}
567
568
const oldFiles = files
569
.filter(file => {
570
const fileDate = new Date(file.created_at || '');
571
return fileDate < cutoffDate;
572
})
573
.map(file => file.name);
574
575
if (oldFiles.length > 0) {
576
const { data, error: deleteError } = await supabase.storage
577
.from(bucketId)
578
.remove(oldFiles);
579
580
if (deleteError) {
581
console.error('Error deleting old files:', deleteError);
582
} else {
583
console.log(`Deleted ${oldFiles.length} old files`);
584
}
585
}
586
};
587
```
588
589
### Error Handling
590
591
```typescript
592
const handleStorageOperation = async () => {
593
try {
594
const { data, error } = await supabase.storage
595
.from('documents')
596
.upload('test.pdf', file);
597
598
if (error) {
599
switch (error.message) {
600
case 'The resource already exists':
601
console.error('File already exists. Use upsert: true to overwrite.');
602
break;
603
case 'The object is too large':
604
console.error('File size exceeds the bucket limit.');
605
break;
606
case 'Invalid MIME type':
607
console.error('File type not allowed for this bucket.');
608
break;
609
default:
610
console.error('Storage error:', error.message);
611
}
612
return;
613
}
614
615
console.log('File uploaded successfully:', data);
616
} catch (err) {
617
console.error('Unexpected error:', err);
618
}
619
};
620
```