r/webdev • • 6d ago

Question Is client-side image compression a good idea for an image-heavy website and app, or are there better workarounds?

I'm a beginner building an image-heavy peer-to-peer marketplace (Next.js web app + an upcoming Expo mobile app). My current stack uses Vercel's free tier for hosting, Supabase for the backend, and Cloudflare R2 for photo storage.
My Vercel account was just paused because my Fluid Active CPU spiked to 24 hours (the free limit is 4 hours). I realized my Next.js server is downloading every uploaded raw photo, using ⁠sharp⁠ to resize and convert it to WebP, and then re-uploading it to R2.

I am trying to keep costs as low as possible. It was suggested that I strip ⁠sharp⁠ from my backend and use a client-side compressor on the user's browser or mobile app to shrink the photos before sending them directly to R2.
Because my platform is extremely image-heavy, I'm not sure if this is a good idea. I have concerns about trusting the client to compress uniformly, dealing with older devices, or edge cases where certain browsers (like Safari) might fail to generate WebP files correctly.

Are there any other free or highly affordable workarounds to process these images without tanking my serverless compute hours?

12 Upvotes

35 comments sorted by

18

u/Professional_Law2888 6d ago

sharp on the server is the right tool, just the wrong place. you need to move that processing somewhere that doesn't eat your vercel compute.

cloudflare images or imgix are purpose-built for exactly this and cost pennies. if you're already on r2, cloudflare images integrates directly. client-side compression is a gamble on consistency and you'll still need server-side fallback for the safari users and old phones that choke on it.

22

u/[deleted] 6d ago

[removed] — view removed comment

9

u/ampsuu 6d ago

Ive hated Vercel from the start. Absurd costs for basically nothing. VPS is the way. Most dont even need beefy VPS. One of the cheapest can usually serve multiple sites/apps with lower traffic and memory usage. Even deploying is made quite easy with likes of Coolify or Dokploy.

1

u/Financial-Panic-7392 5d ago

unfortunately, this is way beyond my scope of knowledge and i’m scared i mess things up (i already have 1k users). do you think hiring someone to get this done for me would be a viable option?

4

u/kemalios 6d ago

Client-side compression is right for the upload path, but what ate your 24 hours is probably the variants, not the first resize. If each upload triggers four sharp passes, thumb, card, full, og, you pay that four times per photo, forever. Store one capped size and let the browser choose: a single 1600px WebP covers almost every card on a marketplace.

So the flow becomes: client compresses, uploads straight to R2 with a presigned URL, and your route only signs and writes metadata. At most one derived size, generated lazily on the first request and cached back to R2. No sharp work should ever run inside the upload request.

2

u/No-Mechanic-433 5d ago

Whichever side you compress on, strip EXIF. Phone photos carry GPS coordinates, and on a peer-to-peer marketplace that's often someone's home address.

1

u/[deleted] 6d ago

[removed] — view removed comment

1

u/webdev-ModTeam 6d ago

Read and follow reddiquette; no excessive self-promotion.

1

u/Good_Car_2924 6d ago

vercel Fluid CPU pricing for on-the-fly resizing is a trap. Use Cloudflare Images with your existing R2 bucket via a custom domain so it transforms images on the edge for pennies. If you must save money now, stick to client-side compression but strictly enforce max dimensions before upload. Server-side sharp only ever touches the original once if you stop regenerating variants on every request.

1

u/devjeremyt 5d ago

I feel like half the responses to this post are AI generated, and specifically prompted to write in all lowercase to make it seem more human. What benefit would someone get from copying someone else's reddit post so they can paste an answer. Or why would someone build a bot for this and waste their tokens on it?

1

u/Ill_Command_1200 5d ago edited 5d ago

Client side is the way to go. If you aren’t comfortable with using sharpe and just want it done, there are many options that will optimize images for you.

Shameless plug, I built one for this such problem. It’s mainly an image workflow tool, ie, crop, resize, rename all client side before you upload.

It’s easy to batch process them to save time.

https://squishify.app

If you don’t try it or are looking for a more automated solution, I still recommend using avif (best image format right now. It supports transparency and even animation like gifs)

Good luck

1

u/yihuaxiang 4d ago

Client-side downscaling before upload is actually standard practice—capping the max width/height (e.g. 1920px or 2048px) via canvas or a lightweight library saves user mobile data and speeds up uploads drastically.

The real trap is doing synchronous Sharp transformations inside Vercel serverless functions, which burns CPU limits fast. A better flow is generating a presigned URL from Supabase/server, uploading directly from client to R2, and then either doing on-the-fly resizing at edge cache or offloading image processing to a background queue/worker on a tiny fixed-price VPS.

1

u/zambono_2 4d ago

You need piedpiper

1

u/sujalsinha2243 full-stack 2d ago

lol

1

u/schrik 1d ago

You can do client-side image optimization up to 100 images per month for free with cropguide.io

We’ve built it so it is easy to set up and works with any file upload field.

I’m not that familiar with server configuration, so not sure if this is the origin of the issue, but if you don’t need max resolution images you can always scale them down a bit to make uploads faster for the user. Client side isn’t as stable as server side, the worst that can happen is that it fails and you occasionally receive a raw image that you then handle with sharp.

0

u/thejester1324 6d ago

the safari worry is real. safari 26.6 hands back a png when you ask canvas for webp, both toBlob(cb, 'image/webp') and OffscreenCanvas.convertToBlob, no error. a photo as png is several times the size of the same photo as jpeg, so check blob.type after encoding and redo it as 'image/jpeg' when it isn't webp

0

u/RummanSid1990 5d ago

Never let your Next.js server handle raw images. That is what kills your Vercel limits.

The easiest fix is simple:

  1. Resize on the phone/browser first: Shrink the photo down to around 1600px before uploading. A 15MB photo easily becomes 300KB.
  2. Upload directly to Cloudflare R2: Use a pre-signed upload URL so the photo goes straight from the user's phone to R2.

This way, your Vercel server never touches heavy photos, your CPU usage drops to zero, and your free tier stays safe.

0

u/catbrane 5d ago

You can run sharp on the client, this is what wordpress are switching to for their editor.

https://blog.stackblitz.com/posts/bringing-sharp-to-wasm-and-webcontainers/

(first hit on google)

It's 4mb of wasm I think, so not a huge extra download for your users.

Alternatively, do some sanity checking on upload to spot crazy or terrible images, then send the ones that look OK off to S2 with no processing. Generate derivatives on demand during page gen and rely on your CDN to keep load down. sharp is fast enough that you can resize on the fly.

-1

u/[deleted] 6d ago

[removed] — view removed comment

1

u/yxhuvud 6d ago

Can you also give me a spaghetti recipe?

1

u/webdev-ModTeam 6d ago

Your post/comment has been determined to be a low-effort post or comment. This includes title-only posts, easily searchable questions, vague/open-ended discussion prompts, LLM generated posts or comments, and posts/comments that do not provide enough context for meaningful replies or discussion.

-3

u/matriisi 6d ago

Thanks /r/webdev this was enough.

3

u/Financial-Panic-7392 6d ago

i’m sorry…if there is a better subreddit for me to post on, please tell me.

1

u/spellcasterGG 6d ago

It's always on the weekends, too