Make a blog article available in its initial HTML

An article URL opens with a heading and spinner. Several seconds later, an effect requests the body and the reader sees the text. The interface appears complete in a screenshot, but the original document response contains no article. A failed script download leaves the visitor with the spinner forever. The page's metadata describes the site generally because its title is not available until the browser fetch completes.
This walkthrough assumes Next.js 15 App Router and a project pinned to 15.1.11. It focuses on public article content. Private account screens and highly interactive editors have different access and state requirements, so do not transfer a public rendering policy to them without examining those requirements.
Inspect the response before changing code
Request the article URL directly and save the HTML response. Search for a distinctive sentence from the body, the article heading, and a useful description. The current DOM after scripts run is a different artifact. A crawler simulation or screenshot can complement the response check, but neither should replace it.
Disable JavaScript in a clean browser context and reload the URL. The article should remain readable if the product intends it to be public reading content. Interactive extras may be unavailable; the meaningful body should not depend on them. Check whether the page has a separate accessibility problem, such as text present in HTML but hidden by a client-controlled loading class.
Trace how the body reaches the component. An effect-based fetch often originated as a quick way to reuse an API endpoint. A client-only rich-text renderer may be another cause. Diagnose whether the missing content comes from data fetching, rendering compatibility, or deliberate route behavior before moving files.
Establish a public article contract
Define the fields necessary to render an article: slug, title, body representation, excerpt, publication status, and meaningful dates. Keep administrative fields outside that public contract. Query published records explicitly. A slug lookup that returns drafts and relies on the page to hide them is fragile when metadata or another route uses the same function.
Choose a body representation that can render consistently on the server. If the database stores structured blocks, write or reuse a server-compatible renderer for the allowed block types. If it stores HTML, sanitize it according to the application's allowed content policy before rendering. Moving unsafe HTML into a Server Component does not remove cross-site scripting risk.
Return a distinguishable missing result. A repository error should remain an operational error, while an unpublished or nonexistent public article should follow the missing-resource path. This distinction determines whether readers see a temporary failure or a misleading claim that the article never existed.
Render the body where the data is available
Keep the route page as a Server Component and call a server-only public repository function. The page can render title and content directly, while small client controls handle bookmarks, sharing, or a collapsible table of contents. Those controls should not own the article's primary data request.
import { notFound } from 'next/navigation'
import { readPublicArticle } from '@/lib/public-articles'
import { ArticleBody } from '@/components/article-body'
export default async function Page({ params }: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
const article = await readPublicArticle(slug)
if (!article) notFound()
return <article>
<h1>{article.title}</h1>
<ArticleBody blocks={article.blocks} />
</article>
}
ArticleBody and readPublicArticle are application abstractions. The renderer needs explicit behavior for unsupported blocks, code samples, lists, and links. Test them with synthetic content instead of assuming an editor's serialized format can be displayed by printing its JSON.
Do not fetch your own API from this page merely to preserve the old endpoint call. A shared server read avoids build-time origin assumptions. The endpoint can remain for browser or external clients and use the same public projection. See server-to-self API calls.
Align the rest of the document
Generate metadata from the same published content contract. The article title, description, canonical URL, and public page should agree about which resource exists. A generic fallback for an operational error can hide a failure and produce misleading metadata. Use a deliberate fallback only when the product intends one.
Make heading structure useful. The route's main title is the primary heading, and body headings should follow a sensible hierarchy. Preserve links and code text in accessible markup. A server renderer that removes all inline structure may technically include words in HTML while making the article much less useful.
Decide which dates mean publication and modification. An unrelated page render should not change the modification date. If structured data is added, serialize it safely and derive its fields from the same public record. Do not invent an author, image, or date to satisfy a template.
Verify useful HTML and later interaction
Use a production build and request a known public article directly. Check the response for its unique sentence and metadata. If streaming or loading boundaries are present, inspect the full delivered response and the user's actual loading experience. A shell that arrives quickly is useful, but it does not by itself prove the article body is available without a separate browser data fetch.
Test long prose, code fences, non-English punctuation, empty optional fields, and unsupported body blocks. Check the generated links and ensure source URLs remain usable. Compare what the editor stores with what the public renderer displays; serialization bugs can silently drop paragraphs.
Then exercise client enhancements after hydration. A bookmark control should not duplicate the main article request, and a sharing control should use the canonical resource URL. Test a script failure or disabled JavaScript path to confirm the enhancements do not hide readable content. The repair is complete only when both initial reading and intended interaction work.
Use AI review to inspect contracts
Provide the body schema, public read, renderer, and route to an assistant. Ask it to find fields assumed by the renderer but absent from stored records. Ask which body types have no explicit rendering case. These are bounded comparisons that produce reviewable findings.
Require file and field evidence for claims about SEO. A statement that server rendering automatically guarantees discovery is too broad. Public accessibility, canonical consistency, status codes, content quality, and discovery links still matter. The assistant can help build the checks; the actual HTTP response and stored data establish the result.
If the body must remain client-rendered because an existing library has unavoidable browser dependencies, first examine whether a separate public renderer is practical. Keeping an editor client-side does not require the reading view to share all editor dependencies. That separation can be simpler than adapting a complex editor runtime to server rendering.
Trade rendering work for a clear reading guarantee
Server rendering moves work and data dependencies into the server path. Decide whether articles can be cached and how publication changes invalidate them. A fully dynamic read may be acceptable for a small site, while larger workloads may need a deliberate freshness policy. Measure rather than assuming either option is free.
Metadata contracts and real missing-resource responses cover the next two checks. Together with readable initial HTML, they make the public route behave like a complete article rather than a browser application that eventually reveals one.
Sources
About the Author

Kamruz
Full Stack Developer
A passionate developer who loves creating modern web applications and sharing knowledge with the community.
More About Me