mirror of
https://github.com/supabase/supabase.git
synced 2026-10-10 03:45:06 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Replaced legacy "Anon"/"Service Role" key terminology with "Publishable Keys" and "Secret Keys" across Edge Functions guides * Updated authentication examples and request headers (client-side vs server-side) to reflect publishable/secret key usage * Standardized environment-variable examples to use parsed secret-key maps with a selectable default * Removed guidance for bypassing JWT verification via the deprecated CLI flag <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Kalleby Santos <kalleby_santos@hotmail.com>
199 lines
6.3 KiB
Plaintext
199 lines
6.3 KiB
Plaintext
---
|
||
id: 'function-ephemeral-storage'
|
||
title: 'File Storage'
|
||
description: 'Use persistent and ephemeral file storage'
|
||
subtitle: 'Use persistent and ephemeral file storage'
|
||
---
|
||
|
||
Edge Functions provides two flavors of file storage:
|
||
|
||
- Persistent - backed by S3 protocol, can read/write from any S3 compatible bucket, including Supabase Storage
|
||
- Ephemeral - You can read and write files to the `/tmp` directory. Only suitable for temporary operations
|
||
|
||
You can use file storage to:
|
||
|
||
- Handle complex file transformations and workflows
|
||
- Do data migrations between projects
|
||
- Process user uploaded files and store them
|
||
- Unzip archives and process contents before saving to database
|
||
|
||
---
|
||
|
||
## Persistent Storage
|
||
|
||
The persistent storage option is built on top of the S3 protocol. It allows you to mount any S3-compatible bucket, including Supabase Storage Buckets, as a directory for your Edge Functions.
|
||
You can perform operations such as reading and writing files to the mounted buckets as you would in a POSIX file system.
|
||
|
||
To access an S3 bucket from Edge Functions, you must set the following for environment variables in Edge Function Secrets.
|
||
|
||
- `S3FS_ENDPOINT_URL`
|
||
- `S3FS_REGION`
|
||
- `S3FS_ACCESS_KEY_ID`
|
||
- `S3FS_SECRET_ACCESS_KEY`
|
||
|
||
[Follow this guide](/docs/guides/storage/s3/authentication) to enable and create an access key for Supabase Storage S3.
|
||
|
||
To access a file path in your mounted bucket from your Edge Function, use the prefix `/s3/YOUR-BUCKET-NAME`.
|
||
|
||
```tsx
|
||
// read from S3 bucket
|
||
const data = await Deno.readFile('/s3/my-bucket/results.csv')
|
||
|
||
// make a directory
|
||
await Deno.mkdir('/s3/my-bucket/sub-dir')
|
||
|
||
// write to S3 bucket
|
||
await Deno.writeTextFile('/s3/my-bucket/demo.txt', 'hello world')
|
||
```
|
||
|
||
## Ephemeral storage
|
||
|
||
Ephemeral storage will reset on each function invocation. This means the files you write during an invocation can only be read within the same invocation.
|
||
|
||
You can use [Deno File System APIs](https://docs.deno.com/api/deno/file-system) or the [`node:fs`](https://docs.deno.com/api/node/fs/) module to access the `/tmp` path.
|
||
|
||
```tsx
|
||
Deno.serve(async (req) => {
|
||
if (req.headers.get('content-type') !== 'application/zip') {
|
||
return new Response('file must be a zip file', {
|
||
status: 400,
|
||
})
|
||
}
|
||
|
||
const uploadId = crypto.randomUUID()
|
||
await Deno.writeFile('/tmp/' + uploadId, req.body)
|
||
|
||
// E.g. extract and process the zip file
|
||
const zipFile = await Deno.readFile('/tmp/' + uploadId)
|
||
// You could use a zip library to extract contents
|
||
const extracted = await extractZip(zipFile)
|
||
|
||
// Or process the file directly
|
||
console.log(`Processing zip file: ${uploadId}, size: ${zipFile.length} bytes`)
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## Common use cases
|
||
|
||
### Archive processing with background tasks
|
||
|
||
You can use ephemeral storage with [Background Tasks](/docs/guides/functions/background-tasks) to handle large file processing operations that exceed memory limits.
|
||
|
||
Imagine you have a Photo Album application that accepts photo uploads as zip files. A streaming implementation will run into memory limit errors with zip files exceeding 100MB, as it retains all archive files in memory simultaneously.
|
||
|
||
You can write the zip file to ephemeral storage first, then use a background task to extract and upload files to Supabase Storage. This way, you only read parts of the zip file to the memory.
|
||
|
||
```tsx
|
||
import { BlobWriter, ZipReader } from 'https://deno.land/x/zipjs/index.js'
|
||
import { createClient } from 'jsr:@supabase/supabase-js@2'
|
||
|
||
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
||
// If you want to use a different api key, change 'default' to your preferred key name
|
||
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, SUPABASE_SECRET_KEYS['default'])
|
||
|
||
async function processZipFile(uploadId: string, filepath: string) {
|
||
const file = await Deno.open(filepath, { read: true })
|
||
const zipReader = new ZipReader(file.readable)
|
||
const entries = await zipReader.getEntries()
|
||
|
||
await supabase.storage.createBucket(uploadId, { public: false })
|
||
|
||
await Promise.all(
|
||
entries.map(async (entry) => {
|
||
if (entry.directory) return
|
||
|
||
// Read file entry from temp storage
|
||
const blobWriter = new BlobWriter()
|
||
const blob = await entry.getData(blobWriter)
|
||
|
||
// Upload to permanent storage
|
||
await supabase.storage.from(uploadId).upload(entry.filename, blob)
|
||
|
||
console.log('uploaded', entry.filename)
|
||
})
|
||
)
|
||
|
||
await zipReader.close()
|
||
}
|
||
|
||
Deno.serve(async (req) => {
|
||
const uploadId = crypto.randomUUID()
|
||
const filepath = `/tmp/${uploadId}.zip`
|
||
|
||
// Write zip to ephemeral storage
|
||
await Deno.writeFile(filepath, req.body)
|
||
|
||
// Process in background to avoid memory limits
|
||
EdgeRuntime.waitUntil(processZipFile(uploadId, filepath))
|
||
|
||
return new Response(JSON.stringify({ uploadId }), {
|
||
headers: { 'Content-Type': 'application/json' },
|
||
})
|
||
})
|
||
```
|
||
|
||
### Image manipulation
|
||
|
||
Custom image manipulation workflows using [`magick-wasm`](/docs/guides/functions/examples/image-manipulation).
|
||
|
||
```tsx
|
||
Deno.serve(async (req) => {
|
||
// Save uploaded image to temp storage
|
||
const imagePath = `/tmp/input-${crypto.randomUUID()}.jpg`
|
||
await Deno.writeFile(imagePath, req.body)
|
||
|
||
// Process image with magick-wasm
|
||
const processedPath = `/tmp/output-${crypto.randomUUID()}.jpg`
|
||
// ... image manipulation logic
|
||
|
||
// Read processed image and return
|
||
const processedImage = await Deno.readFile(processedPath)
|
||
return new Response(processedImage, {
|
||
headers: { 'Content-Type': 'image/jpeg' },
|
||
})
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## Using synchronous file APIs
|
||
|
||
You can safely use the following synchronous Deno APIs (and their Node counterparts) _during initial script evaluation_:
|
||
|
||
- Deno.statSync
|
||
- Deno.removeSync
|
||
- Deno.writeFileSync
|
||
- Deno.writeTextFileSync
|
||
- Deno.readFileSync
|
||
- Deno.readTextFileSync
|
||
- Deno.mkdirSync
|
||
- Deno.makeTempDirSync
|
||
- Deno.readDirSync
|
||
|
||
**Keep in mind** that the sync APIs are available only during initial script evaluation and aren’t supported in callbacks like HTTP handlers or `setTimeout`.
|
||
|
||
```tsx
|
||
Deno.statSync('...') // ✅
|
||
|
||
setTimeout(() => {
|
||
Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context
|
||
})
|
||
|
||
Deno.serve(() => {
|
||
Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## Limits
|
||
|
||
There are no limits on S3 buckets you mount for Persistent storage.
|
||
|
||
Ephemeral Storage:
|
||
|
||
- Free projects: Up to 256MB of ephemeral storage
|
||
- Paid projects: Up to 512MB of ephemeral storage
|