Performance Issue: Slow Page Rendering with Live Supabase Database
I am encountering an issue with my SaaS boilerplate project, which uses Next.js, Supabase, and follows the Turborepo folder structure. I have nearly completed the project, but I am facing a performance problem. When running the project locally, I have connected Supabase using Docker. In development mode, the project works slowly due to compilation time, which is expected. However, when I build the project and run it, everything works smoothly, and all pages render very quickly, within seconds.
But when I deploy the project to Vercel and test it, the performance is slow, similar to the development mode, with pages taking much longer to load. To troubleshoot, I connected my local app to a live Supabase dashboard instead of using the local Docker database, but the issue persists. Even after build and then start the project, it still takes over two seconds to render any page.
I am facing a performance issue where, whenever I visit a page, it always re-renders from scratch, instead of caching the page for faster loading on subsequent visits. Ideally, the page should render faster the second time due to caching. However, when I check the network tab, it shows that the page is being rendered from scratch every time, leading to slower performance on every iteration.
In summary, the project works very fast when connected to the local Docker database or local build, but it becomes very slow when connected to the live Supabase database.
I would appreciate any assistance or guidance on resolving this issue. Thank you 😌
1 Reply
Yes this is how serverless and particularly edge functions work.
First of all pages with dynamic data cannot be cached, you can see this in your build logs, they're likely built as dynamic pages and not static.
Secondly here are some things you can optimize.
- Make sure your vercel server and supabase instance are within the closest proximity possible geographically.
- Cache queries and data in nextjs server side as much as possible using
unstable_cache
or 'use cache'
- Use RSC's whenever possible
- Fetch data as far down the component tree as possible and wrap it in a suspense boundary, so it can be streamed in later when it's ready while the static shell can be returned immediately
Any RSC including pages that has none-cached queries, without a suspense boundary will be completely blocked until the data has been fetched, and no html will be sent to the client until then, with the exception of the layouts. But if you fetch data in a layout then the layout also becomes blocked until resolved.