Next.js Best Practice and Client and Server Component Problem.
Unanswered
Common carp posted this in #help-forum
Common carpOP
Hey everyone, I need some help with a Next.js + Supabase SEO issue
I’m currently working on an SEO-oriented website using the following stack:
Next.js (App Router)
Supabase for backend + CMS
The Problem
Because the website is business/SEO focused, Google crawling and indexing is very important.
Initially, I was fetching data from Supabase inside client components using useEffect.
To do that, I had to mark those components with "use client".
Issue with this approach:
Data is fetched after hydration
Google crawler can’t read the content properly
SEO suffers
What I Tried (Server Component Approach)
To fix SEO, I changed my approach:
Fetch data in the parent server component
Pass that data as props to child components
Avoid useEffect
Keep child components as server components
This works great for SEO Google can read the content properly
New Problem (CMS + Fresh Data)
I also built a CMS using Supabase.
Here’s the issue now:
When the site is deployed, existing database data shows correctly But when I add or update content via the CMS, the changes do NOT reflect on the live website
This happens because:
Server components are cached
Data is not revalidated automatically
Because of this, I’m forced to move back to client components, which again hurts SEO 😞
What I’m Looking For :
I need guidance on:
Best practice for SEO-friendly data fetching in Next.js
How to handle CMS updates with server components
Correct usage of SSR / SSG / ISR / revalidation
How to keep data fresh without breaking SEO
If anyone has faced this before or knows the right architectural approach, I’d really appreciate your help
I’m currently working on an SEO-oriented website using the following stack:
Next.js (App Router)
Supabase for backend + CMS
The Problem
Because the website is business/SEO focused, Google crawling and indexing is very important.
Initially, I was fetching data from Supabase inside client components using useEffect.
To do that, I had to mark those components with "use client".
Issue with this approach:
Data is fetched after hydration
Google crawler can’t read the content properly
SEO suffers
What I Tried (Server Component Approach)
To fix SEO, I changed my approach:
Fetch data in the parent server component
Pass that data as props to child components
Avoid useEffect
Keep child components as server components
This works great for SEO Google can read the content properly
New Problem (CMS + Fresh Data)
I also built a CMS using Supabase.
Here’s the issue now:
When the site is deployed, existing database data shows correctly But when I add or update content via the CMS, the changes do NOT reflect on the live website
This happens because:
Server components are cached
Data is not revalidated automatically
Because of this, I’m forced to move back to client components, which again hurts SEO 😞
What I’m Looking For :
I need guidance on:
Best practice for SEO-friendly data fetching in Next.js
How to handle CMS updates with server components
Correct usage of SSR / SSG / ISR / revalidation
How to keep data fresh without breaking SEO
If anyone has faced this before or knows the right architectural approach, I’d really appreciate your help
31 Replies
Could you just not cache it ?
Or use a webhook in revalidate it?
Common carpOP
this is the current code of mine where I get the problems and there are too many pages also where I get the problem but currently I give one snippet.
@Patrick MacDonald Problem I have mentioned above.
Plz share the snippet here with triple `
code hereCommon carpOP
discord not allowed to paste the code in `````` when I paste it convert them into .txt file.
@Patrick MacDonald
@Patrick MacDonald
sorry i was on my phone i can see it now
To answer your original question, best to do the SEO on the server(layout.tsx) and I like to fetch the data on the server and pass it to a with user() to client or await with server component. Usually I start the promise on the page with out await and pass it as a prop using suspense. As far as getting fresh data you need to not cache the page or revalidate the data some or or by time.
wrapping the child component wheather it be client(if you use use() ) or server in suspense, allows you do show fallback UI as well as not stalling the rest of the UI when using use() or await
lol it was a big question also SSG is when you have a dynamic route '/[slug]' and you use generate static prams to prerender the data allowing the pages to be static, ISR is when you regenerate the data for these pages to keep the fresh. Revalidate is a way to trigger ISR and also get fresh data on pages or layouts or tags for cache data on the server.
Oh I also try to make as many things a server component as possible, client components can be children of server components but server components can not be children of clients unless you pass the server components as props.
Common carpOP
One clarification from my side — I did try forcing dynamic rendering on the parent Blog Archive page using:
export const dynamic = "force-dynamic"
and then fetched the data in the parent Server Component and passed it down to the child components as props.
Even with force-dynamic, when I update or add content via the Supabase CMS, the changes still don’t consistently reflect on the live site after deployment.
export const dynamic = "force-dynamic"
and then fetched the data in the parent Server Component and passed it down to the child components as props.
Even with force-dynamic, when I update or add content via the Supabase CMS, the changes still don’t consistently reflect on the live site after deployment.
that's why I have to rely on the useEffect data fetching.
@Patrick MacDonald
Dose Supabase have webhooks?
@Common carp
Common carpOP
Yes Supabase does support webhooks
you could set up a web hook receive the webhook and use revalidatePath()
the for what every reason the data is cached on the server when the event you looking for on supabase happens it will tell your server to fetch fresh data when ppl request this page
Common carpOP
Just to confirm my understanding — even though Supabase is a Backend-as-a-Service, using a small Next.js API route purely as an orchestration layer (for receiving Supabase webhooks and triggering revalidatePath() / revalidateTag()) is considered best practice and not “rebuilding the backend,” right?
In other words, Supabase still handles the database, auth, and CMS, while Next.js only coordinates caching and ISR for SEO pages.
Just want to be sure I’m following the intended architecture correctly.
In other words, Supabase still handles the database, auth, and CMS, while Next.js only coordinates caching and ISR for SEO pages.
Just want to be sure I’m following the intended architecture correctly.
the route only gets hit when the webhook event happens
its just one route the rest of the app is unchanged
Common carpOP
I’ll go ahead and set this up and try the webhook + revalidation approach.
If I run into any issues while implementing it, I’ll reach out again.
Appreciate your help!
If I run into any issues while implementing it, I’ll reach out again.
Appreciate your help!
supabase with have you store some env's and when the route gets hit only your app will beable to decode it
May I get my answer marked correct?
If you have any more questions about this I have notifications turned on for this post
Common carpOP
Ok.
Thank you 🙂
By the way, I prefer fetching the data on the server AKA starting the promise on the page because it allows the data fetch to start right when the page is being sent to the user instead of the page being sent to the user, it hydrating and then beginning the fetch going back to the server, then back to the database, then back to the server, then back to the client. It stops a lot of unnecessary back and forth and it also allows the page to continue rendering without having to wait for the data to be fetched