PortableText rendering issue only in production build, not in dev
I've seen this issue before! The good news is there's a known solution for this specific problem with Portable Text links showing wrong URLs in Gatsby production builds.
This is actually a React key issue that only manifests in production builds due to how React optimizes rendering. The root cause is typically invalid HTML nesting in your custom serializers/components.
As the original poster discovered in the GitHub issue, the problem was having a <div> nested inside an <a> tag in their custom marks serializer. Block-level elements like div inside inline elements like a creates invalid HTML, which React handles differently in development vs production mode.
The Solution
Change any block-level elements in your link marks to inline elements:
Bad:
marks: {
link: ({value, children}) => (
<a href={value.href}>
<div>{children}</div> // ❌ Block element inside inline
</a>
)
}Good:
marks: {
link: ({value, children}) => (
<a href={value.href}>
<span>{children}</span> // ✅ Inline element
</a>
)
}Or just use the children directly:
marks: {
link: ({value, children}) => (
<a href={value.href}>{children}</a>
)
}Why This Happens
- In development, React is more forgiving with invalid HTML nesting
- In production builds, React's optimizations cause it to reuse DOM nodes incorrectly when the HTML structure is invalid
- This leads to href attributes getting "stuck" on the wrong links
- Gatsby's SSR/hydration process amplifies this issue
Additional Checks
If you've already migrated to @portabletext/react (the modern replacement for the deprecated block-content-to-react), make sure you're also:
- Providing proper
keyprops if you're mapping over custom components - Not wrapping marks in block-level elements
- Following proper HTML semantics in all your custom serializers
This production-only bug with reused URLs is almost always a sign of invalid HTML nesting in your Portable Text components!
Show original thread11 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.