or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mddatabase.mdfunctions.mdindex.mdrealtime.mdstorage.md

storage.mddocs/

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

```