Partly fixable yourself. A config line or a bucket setting, under an hour.
What you see. Pictures and uploaded files show as broken icons or alt text on the live site but worked in preview.
Why it happens
There are three usual causes, and the status code in the Network tab tells them apart. First, Next.js only loads remote images from hosts listed under images.remotePatterns in next.config.js. If your Supabase storage host is not listed, the image request fails. Second, Supabase storage buckets are private by default. Files in a private bucket can only be fetched with a signed URL or an authorized download. A plain public URL returns an error. Public buckets skip access checks for reads.
Third, on the Vercel Hobby plan image optimization includes 5,000 transformations a month. Past that, new images fail with a 402 and the alt text shows instead. Smaller causes are a file that was never committed to the repository and file names whose case differs, since the server is case sensitive and your laptop may not be.
Fix it yourself
- Press F12, open Network, filter by Img and click a broken image. 400 from
/_next/imagemeans the host is not allowed, 403 from Supabase a private bucket, 402 the Vercel limit, 404 a wrong path. - Next.js: add your project host to
images.remotePatternsinnext.config.jswith protocol https, hostnameyourproject.supabase.coand pathname/storage/v1/object/public/**. Redeploy. - Supabase: open Storage and the bucket. Public images like logos can live in a public bucket. User documents stay private and the app must use
createSignedUrl. Do not make a private bucket public just to fix a bug. - Check that the file really exists in the bucket or in the
publicfolder of your repository, with the exact same upper and lower case as the code. - Hit the Vercel limit: add
unoptimizedto those images or move to a paid plan. Already cached images keep working. - Retest in a private window, since the browser may have cached the broken response.
When to get an engineer
Get an engineer when uploads from users are involved, because a wrong bucket setting can expose private files to anyone with the link. Tell them the status code, the failing URL, and which bucket holds the files. A single fix is €99–$990, about two days. Ask them to confirm every bucket is private where it should be, which is check DATA-04 on the checklist.
Top-rated companies for Supabase apps
Ranked by our score: published prices, scope of work, AI tools named, timing and a low-risk first step. How we score.
- 1Redlab10.0/10Best for: A full rescue by one team that keeps buildingFree first step · from $490
- 2Vibe Code Rescue (Lev Arakelyan)9.0/10Best for: A one-off check and a cleanupFrom $299
- 3LazyCodeLab9.0/10Best for: A one-off check and a cleanupFrom $399
Check these
File storage is private where it should be
Upload a private file, copy its URL, and open it in a private window. If it loads, the bucket is public.
Images are resized and compressed
Uploaded photos served at full size are a common cause of slow pages.
Key pages load fast on a phone
Run PageSpeed Insights on the home page and the main app screen, on mobile.
Secrets live in the host's environment settings
Keys belong in environment variables on the server, not in the repository or in front-end code.
Questions
Should I just make all buckets public?
Only for files that anyone may see, like product photos. Invoices, ID scans and private uploads belong in a private bucket with signed URLs.
Why does the preview load the images?
The preview may run without Next.js image optimization, or you were signed in as the owner, who could read the private bucket.
Sources: Next.js: Image component; Supabase: storage buckets; Supabase: storage access control; Vercel: image optimization limits.
