Auto‑Resize Images with Supabase Storage + Edge Functions: A Practical Guide
Learn how to trigger an Edge Function on Supabase Storage uploads, use Sharp to resize images, and store the result back to the bucket. Includes code, trade‑offs, and a step‑by‑step example.
16 Sept 2026, 04:23 UTC

Problem: Manual Image Resizing Is a Bottleneck
Web and mobile apps that let users upload photos often need thumbnails or optimized sizes for quick display. Doing this on the client is error‑prone, and doing it on a traditional server adds latency, scaling complexity, and cost. The question is: can we resize images automatically, right after upload, without a dedicated backend?
Thesis: Use Supabase Storage’s Event Triggers and Edge Functions
Supabase Storage is S3‑compatible object storage with built‑in event triggers. When an object is created, a storage:object:created event is emitted. Edge Functions run serverless JavaScript/TypeScript at the network edge, making them ideal for low‑latency, per‑upload image processing.
1️⃣ Set Up the Project
- From the Supabase dashboard, create a new project (or use an existing one).
- Enable Storage and Functions in the sidebar.
- Run the CLI to scaffold the functions directory:
supabase init - Navigate to
functionsand create a new function namedresize-image:supabase functions new resize-image - Add the
sharplibrary to the function’spackage.json.cd functions/resize-image npm install sharp - Configure the function’s
function.jsonto listen to the storage event:{ "events": ["storage:object:created"], "config": { "bucket": "uploads", "pathPrefix": "images/" } }
2️⃣ Write the Resize Handler
The handler receives the event payload, downloads the original image, runs Sharp, and writes the resized file back to a dedicated bucket (e.g., thumbnails) so the original remains untouched.
import { createReadStream, createWriteStream } from 'fs';
import sharp from 'sharp';
import { storage } from '@supabase/supabase-js';
export default async function eventHandler(event, context) {
const { bucket, key } = event;
const supabaseUrl = process.env.SUPABASE_URL;
const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
const supabase = storage.createClient(supabaseUrl, supabaseKey);
// Download original image
const { data: originalStream, error: downloadErr } = await supabase
.from(bucket)
.download(key);
if (downloadErr) throw downloadErr;
// Resize using Sharp (e.g., 300x300 px)
const resizedBuffer = await sharp(originalStream)
.resize(300, 300)
.toBuffer();
// Upload resized image to thumbnails bucket
const thumbnailKey = key.replace('images/', 'thumbnails/');
const { error: uploadErr } = await supabase
.from('thumbnails')
.upload(thumbnailKey, resizedBuffer, {
contentType: 'image/jpeg',
cacheControl: '3600',
upsert: true
});
if (uploadErr) throw uploadErr;
return { status: 200, body: 'Resized image stored' };
}
Replace SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY with your project’s values (stored as environment variables in the function).
3️⃣ Deploy and Test
- Deploy the function:
supabase functions deploy resize-image - Upload a test image to
uploads/images/using the REST endpoint or SDK.curl -X POST -H "Authorization: Bearer $SUPABASE_ANON_KEY" \ -F "file=@/path/to/photo.jpg" \ "$SUPABASE_URL/storage/v1/object/uploads/images/photo.jpg" - Check the Supabase dashboard → Storage → thumbnails bucket. The resized
photo.jpgshould appear. - View function logs to confirm Sharp processed the image. The logs will show the invocation time and any errors.
4️⃣ Trade‑Offs & Limitations
- Execution Time: Edge Functions have a 10 s limit. Very large images (e.g., >10 MB) may exceed this. Consider pre‑validating size or using a longer‑running worker if needed.
- Cold Starts: The first invocation after inactivity adds latency (~200–300 ms). For high‑traffic apps, the impact is minimal but worth measuring.
- Binary Dependencies: Sharp requires native bindings. The Supabase Edge runtime includes the necessary libraries, but if you add custom modules, ensure compatibility.
- Cost: Storage for both original and resized images doubles storage usage. Use lifecycle rules to delete thumbnails after a set period if they’re temporary.
- Invocation Quotas: Edge Functions have a monthly invocation cap (e.g., 100 k). For very high upload volumes, monitor usage or split the workload across multiple functions.
- Error Handling: If the function fails after downloading the image, the original remains. Implement retry logic or a dead‑letter queue if consistency is critical.
Actionable Takeaway
By wiring Supabase Storage events to an Edge Function that uses Sharp, you get a fully serverless, low‑latency image resize pipeline that scales automatically with your traffic. The steps are straightforward: enable Storage & Functions, write a lightweight handler, deploy, and test. Keep an eye on execution time and storage costs, and add error handling for production readiness.
Next time a user uploads a photo, your app can instantly serve a ready‑made thumbnail without any manual intervention or dedicated backend.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.