SolidJS SEO
How to make SolidJS sites crawlable, indexable, and fast — why bare SolidJS is CSR-only, how SolidStart's SSR/SSG fixes it, managing head tags with @solidjs/meta, and why SolidJS hydrates (it is not resumable like Qwik).
SolidJS is a fast, React-like library with fine-grained reactivity and no virtual DOM — but on its own it's client-side rendered, so it ships an empty HTML shell with the same indexing problems as bare React. The fix is SolidStart, the official meta-framework: SSR or SSG put real content and metadata in the first response. Manage head tags with @solidjs/meta (<Title>, <Meta>, <Link>), return real 404s with <HttpStatusCode>, and fetch data on the server with createAsync. One thing not to mix up: SolidJS hydrates — it is not resumable. Resumability is Qwik's trick. SolidJS's win is a Core Web Vitals edge on top of standard SSR.
Evidence for this claim The article's described solidjs-seo capabilities must be evaluated against the platform's current documentation rather than assumed to be search-engine behavior. Scope: Platform-specific capability documentation. Confidence: high · Verified: SolidStart documentation Evidence for this claim Regardless of platform, Google needs crawlable URLs, accessible rendered content, descriptive metadata, and valid search directives. Scope: Google requirements independent of platform. Confidence: high · Verified: Google Search Central: SEO Starter GuideTL;DR — SolidJS is a fast, React-like library, but on its own it builds the page in your browser — so search engines first see an empty shell. The fix is SolidStart, its official full-stack tool, which sends finished HTML to both users and crawlers. Rendering mode is a per-route setting, not a whole-site switch — use server rendering (SSR or SSG) on the routes that need to rank, set your title and meta tags with @solidjs/meta, and verify each route’s actual HTML output rather than assuming the whole site is covered.
What SolidJS is
SolidJS is a JavaScript library for building user interfaces. If you’ve seen React, it’ll look familiar — it uses the same JSX syntax and a similar component style. The big difference under the hood is that SolidJS has no virtual DOM: it updates the exact pieces of the page that change, which makes it very fast.
The catch for SEO: by default, SolidJS is client-side rendered (CSR). The server sends an almost-empty HTML file, then your browser downloads the JavaScript and builds the page. That’s a problem because the first thing a search engine sees is the empty version — no text, no title, no meta description.
Why CSR is an SEO problem
When Google crawls a CSR page, it sees the empty shell first. It can come back later, run the JavaScript, and read the real content — but that second pass can take anywhere from hours to weeks. Worse, Bing and social-media crawlers (Facebook, LinkedIn, X) often don’t run JavaScript at all, so they may never see your content or your share previews.
This is the same issue bare React, Vue, and Angular have. It’s not unique to SolidJS — it’s a property of client-side rendering. (See JavaScript SEO for the full picture.)
The fix: SolidStart
SolidStart is the official meta-framework for SolidJS — think of it as SolidJS’s version of Next.js (for React) or Nuxt (for Vue). It lets the server send finished HTML, so search engines and social crawlers get your content on the very first request. Two main modes:
- SSR (server-side rendering) — the page is built on the server each time it’s requested. Good for content that changes often.
- SSG (static site generation) — pages are built once at deploy time and served as plain files. Fastest option; ideal for blogs, docs, and marketing pages.
Setting your title and meta tags
To control your <title>, meta description, and social share tags, use the
@solidjs/meta package. It gives you <Title>, <Meta>, and <Link>
components you drop into your pages — SolidJS’s equivalent of React Helmet. With
SolidStart’s SSR turned on, those tags show up in the HTML that crawlers read.
The one thing not to mix up
You may hear SolidJS lumped in with Qwik as “the resumable frameworks.” That’s wrong. Resumability is Qwik’s idea. SolidJS uses ordinary hydration — it just does it more cheaply than React. For SEO that distinction barely matters (both put content in the HTML), but it’s a common mistake.
Want the real mechanics — SSR vs. SSG vs. streaming, the @solidjs/meta API, real 404s, server-side data fetching, and the Core Web Vitals story? Switch to the Advanced tab.
Evidence for this claim The article's described solidjs-seo capabilities must be evaluated against the platform's current documentation rather than assumed to be search-engine behavior. Scope: Platform-specific capability documentation. Confidence: high · Verified: SolidStart documentation Evidence for this claim Regardless of platform, Google needs crawlable URLs, accessible rendered content, descriptive metadata, and valid search directives. Scope: Google requirements independent of platform. Confidence: high · Verified: Google Search Central: SEO Starter GuideTL;DR — SolidJS is fine-grained reactive (signals, no virtual DOM) and ships as a CSR library by default — an empty shell with the same Wave-1 indexing problem as bare React. SolidStart is the fix: SSR, SSG (route prerendering), and streaming SSR put content and metadata in the first response. Manage head tags with @solidjs/meta (
<Title>,<Meta>,<Link>under a<MetaProvider>), return real status codes with<HttpStatusCode>, and load data on the server withcreateAsyncso it lands in the SSR HTML. The accuracy spine: SolidJS hydrates — it is NOT resumable (that’s Qwik). Its fine-grained reactivity is a client update optimization, not a server-to-client startup one — so the SEO upside is mostly a Core Web Vitals (INP/TBT) edge layered on top of normal SSR.
SolidJS architecture: what’s actually different
SolidJS uses JSX that looks identical to React’s, plus hooks-like primitives
(createSignal, createEffect, createMemo). But the execution model is
fundamentally different:
- React re-runs the whole component function when state changes and diffs a virtual DOM to decide what to update.
- SolidJS compiles JSX to real DOM operations at build time. Components run once; reactive signals wire values directly to the specific DOM nodes that depend on them. When a signal changes, Solid updates only that node — no reconciliation, no virtual DOM overhead.
This is why SolidJS consistently sits near the top of the js-framework-benchmark suite, and why its runtime is dramatically leaner than React’s re-render model. The library itself is roughly 7KB gzipped. Smaller, surgical updates plus a tiny runtime is the performance story — but none of that changes the rendering mode, which is what decides your SEO fate.
CSR by default: the SEO problem
Build with SolidJS alone (no SolidStart) and you get a client-side-rendered app:
- The server sends
index.htmlwith a near-empty body — typically a<div id="root"></div>and a script tag. - The browser downloads the JS bundle, runs Solid’s reactive code, and populates the DOM.
- Googlebot’s first wave sees the empty shell — no content, no metadata.
- Googlebot’s second wave (the rendering queue) eventually runs the JS and sees content — but the timing is unpredictable, from hours to weeks.
- Bing, social crawlers, and non-JS bots may never see the content at all.
This is the two-wave rendering process, and it’s the same trap any CSR SPA falls into. The practical impacts: slow initial indexing of new content; titles and meta descriptions missing from the raw HTML (so wrong/blank snippets in SERPs); and soft 404s, because a CSR app can’t return a true HTTP 404 — the server always answers 200 with the app shell.
SolidStart: the fix
SolidStart (1.0, stable) is the official SolidJS meta-framework, built on Vinxi (Vite + Nitro). It provides:
- Isomorphic, file-based routing — files under
src/routes/map to URLs (src/routes/blog/[slug].tsx→/blog/:slug). One correction worth being precise about: SolidStart itself does not ship a router or metadata library bundled in — per its own docs, “SolidStart itself does not ship with a Router or Metadata library. Rather, it leaves that open for you to use any library you want.” The routing and@solidjs/metabehavior described here come from adding@solidjs/routerand@solidjs/metaexplicitly (the official templates add both for you, which is why it can feel automatic — check yourpackage.jsonrather than assuming they came free with the framework). - Multiple rendering modes, chosen per route: CSR, SSR (synchronous, asynchronous, or streaming), and SSG / route prerendering. A SolidStart project isn’t “SSR” or “CSR” as a whole — each route picks its own mode, so verify the rendering config (and the resulting HTML) for the specific route you care about rather than assuming the whole site inherited one setting.
- Server functions — a
"use server"directive for RPC-style server code (data fetching, database access). - Adapters for Cloudflare, Vercel, Netlify, Deno, Node, and static hosting.
Version note: this reflects SolidStart 1.0’s current documentation, which labels itself beta and was last updated 2026-04-28 — confirm details against the docs for the version you’re actually running before treating any of this as permanent API surface.
SSR vs. SSG vs. streaming — the SEO read
- SSR (synchronous, asynchronous, or streaming — SolidStart names these as distinct sub-modes) delivers full content on the first request and is fully indexable on Wave 1. Best for frequently changing pages.
- SSG (route prerendering) builds HTML at deploy time — the fastest TTFB and
LCP, CDN-cacheable, no per-request server work. Best for blogs, docs, and
marketing pages. Configure prerendered routes in
app.config.ts:
// app.config.ts
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({
server: {
prerender: {
routes: ["/", "/about", "/blog"],
},
},
});- Streaming SSR sends HTML progressively to improve TTFB on data-heavy pages; Google renders the full streamed output.
- CSR is fine for authenticated dashboards and tools that don’t need to rank — not for public content.
Managing head tags with @solidjs/meta
The @solidjs/meta package is the SolidJS equivalent of React Helmet or
Next.js’s <Head>. It’s SSR-ready and asynchronous. Wrap your app in
<MetaProvider> so tags are collected during SSR, then set per-page tags inside
your route components:
// src/routes/about.tsx
import { Title, Meta, Link } from "@solidjs/meta";
export default function AboutPage() {
return (
<>
<Title>About Us — My Site</Title>
<Meta name="description" content="Learn more about us." />
<Link rel="canonical" href="https://example.com/about" />
<Meta property="og:title" content="About Us" />
<Meta property="og:description" content="Learn more about us." />
<Meta property="og:image" content="https://example.com/og-about.jpg" />
<main>...</main>
</>
);
}The components available are <Title>, <Meta>, <Link>, <Style>,
<Base>, and the <MetaProvider> wrapper. Deduplication is built in:
<Meta> tags with matching name attributes override parent definitions — the
deepest (most specific) one wins, and this works correctly during SSR. So a root
default title and per-page overrides behave as you’d expect.
One warning straight from the docs: don’t add raw <title> tags in your
server files — they override @solidjs/meta’s functionality. Always use the
<Title> component, never a hand-written HTML title in your server template.
Structured data (JSON-LD)
Google supports JSON-LD whether it’s in the raw HTML or injected by JavaScript, but SSR-rendered JSON-LD is the reliable choice. In SolidStart, render it in the route component:
export default function ArticlePage() {
const schema = {
"@context": "https://schema.org",
"@type": "Article",
"headline": "My Article",
"author": { "@type": "Person", "name": "Author Name" },
};
return (
<>
<script
type="application/ld+json"
innerHTML={JSON.stringify(schema)}
/>
<article>...</article>
</>
);
}With SSR enabled, the JSON-LD appears in the server-rendered HTML — the preferred approach for reliability across every crawler. Validate with the Rich Results Test or URL Inspection Tool.
Hydration, not resumability — the accuracy spine
Hydration is the process where, after SSR delivers rendered HTML, the
framework attaches to the existing DOM to make it interactive: download the JS
bundle, execute the framework code, reconcile state with the existing nodes,
attach event listeners. SolidJS uses hydration — the same fundamental mechanism
as React’s hydrate, Vue’s createSSRApp, or Angular SSR.
Resumability (Qwik’s architecture) is different: the server serializes the framework’s execution state into the HTML, and the client resumes from there without re-executing components — interactive before any JS runs.
The myth to debunk: SolidJS’s fine-grained reactivity is sometimes confused with resumability because both avoid “re-running” components in the traditional sense. They are not the same thing. Fine-grained reactivity is a client-side update optimization; resumability is a server-to-client startup mechanism. SolidJS still downloads and runs its runtime before the page is interactive.
The SEO implication: both SSR+hydration (SolidJS) and resumability (Qwik) put rendered HTML in the server response, so both are good for indexing. The difference is Time to Interactive and INP on slow devices, where Qwik’s near-zero startup JS has the edge. For crawl and index, SolidStart SSR is already enough.
Core Web Vitals
SolidJS’s runtime advantages can translate into better Core Web Vitals scores on routes that use SSR — but this isn’t automatic or universal. No primary source establishes guaranteed cheap hydration or better outcomes for every Solid/SolidStart route: bundle size, data fetching, third-party scripts, device, and the route’s actual rendering mode all determine the real cost. Treat the following as the mechanism by which SolidJS can help, and measure your own routes to confirm it does:
- LCP improves because the largest content element is in the server-rendered HTML — no waiting on JS.
- INP improves because Solid’s fine-grained runtime handles interactions efficiently (no virtual DOM diffing).
- CLS drops because SSR’d content doesn’t shift as late-loading JS fills in.
A caution worth keeping honest: figures like “SolidJS is ~70% faster than React’s virtual DOM” come from synthetic benchmarks (js-framework-benchmark), not real-world field data. Real CWV depends far more on implementation quality, data fetching, and hosting than on framework choice. Treat the benchmark numbers as directional, and measure your own field data in CrUX / Search Console.
Routing, data fetching, and real 404s
Routing. SolidStart uses the History API by default — never use
hash-based (#/page) routing, which prevents reliable URL discovery. Keep
trailing-slash behavior consistent and enforce it with server redirects, not
just canonicals.
Data fetching for SEO. Content that needs to rank must be loaded on the
server so it’s in the SSR HTML. Use createAsync and server functions — not
onMount or client-side effects, which run after the HTML is sent:
// Server-side data fetch — content lands in the initial HTML ✓
import { createAsync } from "@solidjs/router";
import { getPost } from "~/lib/api";
export const route = {
load: ({ params }) => getPost(params.slug),
};
export default function BlogPost(props) {
const post = createAsync(() => getPost(props.params.slug));
return <article>{post()?.content}</article>;
}Real 404s. A catch-all route plus <HttpStatusCode> from @solidjs/start
sets the actual HTTP response code on the server — a true 404 instead of a soft
404:
// src/routes/[...404].tsx
import { HttpStatusCode } from "@solidjs/start";
export default function NotFound() {
return (
<>
<HttpStatusCode code={404} />
<h1>Page Not Found</h1>
</>
);
}Sitemaps, robots.txt, and international SEO
- robots.txt — add
public/robots.txtat the project root and point it at your sitemap. Don’t block the/api/routes used for XHR data fetching. - Sitemap — the third-party
solid-start-sitemapplugin (by madaxen86) generatessitemap.xmlat build time and supports dynamic routes via parameter mapping or a runtime API route. - International SEO — emit hreflang with
<Link rel="alternate" hreflang="…">from @solidjs/meta, and use a subdirectory structure (/en/,/fr/) over subdomains or query parameters.
Common SolidJS SEO pitfalls
- Running SolidJS CSR without SolidStart SSR/SSG.
- Fetching rankable content in
onMount/ client-side effects. - Forgetting the
<MetaProvider>wrapper (tags won’t render in SSR). - Adding raw
<title>HTML tags in server templates (overrides @solidjs/meta). - Using hash-based routing.
- Serving soft 404s without
<HttpStatusCode>. - Blocking API routes in robots.txt.
- Not fingerprinting JS assets (Google caches scripts aggressively).
- Content behind a click/accordion/tab that never auto-loads into the DOM.
- Assuming SSR works without verifying via View Source / URL Inspection.
- Assuming
@solidjs/routerand@solidjs/metacome bundled with SolidStart — they don’t; SolidStart’s own docs say it “does not ship with a Router or Metadata library.” Official templates add both for you, but a from-scratch or customized setup needs them installed explicitly. - Treating a project as uniformly “SSR” or “CSR” — rendering mode is set per route in SolidStart, so a route you assume is server-rendered may not be.
Where this sits
SolidJS lives in the JavaScript frameworks subcluster alongside Qwik, under the broader JavaScript SEO cluster. For the closest parallel, see React SEO — SolidJS shares React’s JSX and CSR-by-default problem, but fixes it with SolidStart instead of Next.js, and runs faster thanks to no virtual DOM. For how Google sees rendered content, see rendering and crawling.
AI summary
A condensed take on the Advanced version:
- SolidJS = fine-grained reactivity, no virtual DOM. Components run once; signals update only the exact DOM nodes that change. Tiny runtime (~7KB), consistently near the top of js-framework-benchmark, faster than React’s re-render model.
- Bare SolidJS is CSR by default — an empty HTML shell. Same Wave-1 indexing problem as bare React/Vue/Angular: Googlebot’s first wave sees no content, rendering is queued (hours to weeks), and Bing/social crawlers may never see it. Soft-404 risk too (CSR can’t return a real 404).
- SolidStart is the fix, per route — the official meta-framework offers CSR, SSR (sync, async, or streaming), and SSG per route; it doesn’t default the whole project to SSR. SSR/SSG routes put content + metadata in the first response, fully indexable on Wave 1 — verify the specific route rather than assuming site-wide coverage.
- Router and metadata aren’t auto-bundled. SolidStart’s own docs say it
ships without a router or metadata library —
@solidjs/routerand@solidjs/metaare explicit additions the official templates happen to include. - Head tags via @solidjs/meta:
<Title>,<Meta>,<Link>under<MetaProvider>; deduplication works in SSR; never use raw<title>in server files. - Real 404s with
<HttpStatusCode>; server-side data withcreateAsync(notonMount); History API routing (no hash routes); JSON-LD rendered in the route component. - Accuracy spine: SolidJS hydrates — it is NOT resumable. Resumability is Qwik’s. Fine-grained reactivity is a client-update optimization, not a startup one. Both SSR+hydration and resumability are good for indexing; Qwik only wins on Time to Interactive.
- CWV upside is possible, not guaranteed (on SSR’d routes): better LCP, INP, and CLS are plausible outcomes — but benchmark gaps are synthetic, and real field data depends on implementation, data, and hosting, not framework choice alone.
Official documentation
Primary-source documentation from Google and the SolidJS team.
Google — JavaScript SEO
- Understand JavaScript SEO Basics — the crawl → render → index pipeline and the two-wave process.
- Dynamic Rendering as a Workaround — why Google deprecated dynamic rendering in favor of SSR, static rendering, and hydration.
- SEO Guide for Web Developers — the developer-facing fundamentals.
SolidJS / SolidStart
- SolidJS documentation — the official docs home.
- Fine-Grained Reactivity — the signals model and how updates target individual DOM nodes.
- SolidStart — the meta-framework: SSR, streaming, routing, server functions.
- SolidStart — Head and Metadata — managing title/meta/link tags for SEO.
- SolidStart — Route Pre-rendering — configuring SSG.
@solidjs/meta
- solid-meta GitHub repository — source and API reference.
- @solidjs/meta on npm — the package.
- Title component docs and Meta component docs.
Quotes from the source
On-the-record statements from Google on JavaScript SEO, plus the SolidJS team’s own framing.
Google — how JavaScript apps are processed
- “Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.” — Google Search Central. Understand JavaScript SEO Basics
- “It’s fine to use JavaScript to inject links into the DOM, as long as such links follow the best practices for crawlable links.”
— Google Search Central (use
<a href>, notonclickorjavascript:void(0)). Understand JavaScript SEO Basics - “You shouldn’t use JavaScript to change the canonical URL to something else than the URL you specified as the canonical URL in the original HTML.” — Google Search Central. Understand JavaScript SEO Basics
- “Use the History API to implement routing between different views of your web app.” — Google Search Central (i.e. no fragment/hash routing). Understand JavaScript SEO Basics
SolidJS team — fine-grained reactivity (paraphrased framing)
- SolidStart’s head-and-metadata docs warn: “Be sure to avoid adding any normal
<title />tags in any server files, as they would override the functionality of @solidjs/meta.” SolidStart — Head and Metadata
SolidJS SEO checklist
A pass to confirm a SolidJS site is crawlable, indexable, and fast:
- You’re using SolidStart with SSR or SSG — not bare SolidJS in CSR mode.
- View Source shows real content and
<a href>links in the raw HTML — not just<div id="root"></div>. - App is wrapped in
<MetaProvider>so head tags render during SSR. -
<Title>and<Meta name="description">set per route via @solidjs/meta. - No raw
<title>tags in server files (they override @solidjs/meta). - Open Graph + Twitter tags present via
<Meta property="og:…">so social previews work. - Canonical set with
<Link rel="canonical">(not changed via JS after load). - Routing uses the History API — no hash (
#/page) routes. - Rankable content loaded with
createAsync/server functions, notonMount. - Missing pages return a real 404 via
<HttpStatusCode code={404} />. -
public/robots.txtexists, points to the sitemap, and doesn’t block/api/data routes. - XML sitemap generated (e.g.
solid-start-sitemap) with canonical URLs. - JSON-LD rendered in the route component and present in the SSR HTML.
- URL Inspection (Search Console) confirms the rendered HTML matches.
- Field Core Web Vitals checked in CrUX / Search Console, not just lab.
The mental models
1. Library vs. meta-framework. SolidJS (the library) decides how the UI updates; SolidStart (the meta-framework) decides where it renders. SEO is governed by the second one. Bare SolidJS = CSR = empty shell. SolidStart SSR/SSG = content in the HTML. Always locate which one you’re actually shipping.
2. The rendering-mode ladder. For any route, pick the highest rung the content allows: SSG (static, fastest, best for stable content) → SSR (dynamic, per-request) → streaming SSR (data-heavy) → CSR (only for non-ranking, authenticated views). Higher rungs are better for both crawlers and Core Web Vitals.
3. Two waves, one goal. Google crawls in Wave 1 (raw HTML) and renders in Wave 2 (queued). The entire point of SolidStart SSR is to make your content complete in Wave 1 so you never depend on the unpredictable Wave 2 queue.
4. Hydration ≠ resumability. SolidJS hydrates (download → execute → attach). Qwik resumes (no re-execution). Fine-grained reactivity speeds the updates after hydration; it doesn’t remove hydration. Keep this straight and you’ll never miscategorize SolidJS.
5. Server-load for anything that must rank.
If content is fetched in onMount, it lands after the HTML is sent — invisible
to Wave 1. Fetch it with createAsync/server functions so it’s baked into the
SSR response.
SolidJS SEO — cheat sheet
SolidJS vs. SolidStart
| SolidJS (library) | SolidStart (meta-framework) | |
|---|---|---|
| Default rendering | CSR (empty shell) | SSR (content in HTML) |
| Rendering modes | CSR only | SSR, SSG, streaming, CSR |
| Meta tags in raw HTML | No (set client-side) | Yes (@solidjs/meta + SSR) |
| Real HTTP 404 | No (soft 404) | Yes (<HttpStatusCode>) |
| Sitemap generation | Manual | solid-start-sitemap plugin |
| SEO verdict (per route) | Risky unless you build in SSR/SSG yourself | Can be SEO-viable — verify each route’s actual rendering mode and output; SolidStart doesn’t guarantee it site-wide |
@solidjs/meta components
| Component | Sets |
|---|---|
<MetaProvider> | Wrapper that collects tags during SSR (required) |
<Title> | <title> |
<Meta> | description, robots, OG, Twitter cards |
<Link> | canonical, hreflang, preload, stylesheets |
<Style> / <Base> | inline <style> / <base> |
Do / don’t
- ✅ Use
<Title>from @solidjs/meta. ❌ Raw<title>in server files. - ✅ History API routing. ❌ Hash (
#/page) routing. - ✅
createAsync/ server functions for rankable data. ❌onMountfetch. - ✅
<HttpStatusCode code={404} />. ❌ Soft 404 (200 + shell).
Myth-busting
- ❌ “SolidJS is resumable like Qwik.” → It hydrates (cheaply); only Qwik resumes.
- ❌ “SolidJS is bad for SEO.” → Bare CSR is; SolidStart SSR/SSG is fully indexable.
- ❌ “Google can’t read SolidJS.” → It can (modern Chromium); the risk is Wave-2 delay, removed by SSR.
SolidJS SEO mistakes to avoid
Shipping public content with bare SolidJS CSR
Why it’s wrong: The first response is an app shell, so crawlers do not receive the page’s content or metadata immediately. Do this instead: use SolidStart SSR or route prerendering for every public route that needs to rank.
Fetching rankable data in onMount
Why it’s wrong: onMount runs after the server response, leaving the content out
of raw HTML. Do this instead: fetch with createAsync, route loaders, or server
functions so the data is present during SSR.
Forgetting MetaProvider or adding a raw title
Why it’s wrong: Without MetaProvider, @solidjs/meta cannot collect tags for SSR;
a raw <title> in a server file can override its output. Do this instead: wrap
the app in MetaProvider and use <Title>, <Meta>, and <Link> consistently.
Using hash routes or soft 404s
Why it’s wrong: #/page routes are poor discovery targets, and a missing page
that returns HTTP 200 looks like a soft 404. Do this instead: use History API
routes and set a real status with <HttpStatusCode code={404} />.
Calling fine-grained reactivity resumability
Why it’s wrong: SolidJS still hydrates; it does not resume server execution state the way Qwik does. Do this instead: describe Solid’s advantage as efficient client updates, then verify the actual server rendering and field performance.
Trusting SSR without checking the response
Why it’s wrong: A route can use SolidStart and still leave copy, metadata, or JSON-LD in client-only code. Do this instead: inspect View Source and the initial network response after every rendering or data-loading change.
Audit a SolidStart response from the command line
macOS / Linux — inspect status, metadata, and body content
URL="https://example.com/blog/example-post"
curl -sSIL "$URL" | sed -n '1,12p'
curl -sSL "$URL" -o /tmp/solidstart-page.html
grep -Ei '<title>|name="description"|rel="canonical"|<h1|application/ld\+json' \
/tmp/solidstart-page.htmlThe first response should be a real success status for a live route, and the raw HTML should contain the route’s title, description, canonical, H1, and any JSON-LD without running JavaScript.
Windows PowerShell — run the same raw-HTML check
$url = "https://example.com/blog/example-post"
$response = Invoke-WebRequest -Uri $url
$response.StatusCode
$response.Content | Select-String -Pattern '<title>|name="description"|rel="canonical"|<h1|application/ld\+json'Check a missing route returns a true 404
curl -sS -o /dev/null -w '%{http_code}\n' \
'https://example.com/this-route-should-not-exist'
# Expected: 404DevTools Console — list the rendered head signals
({
title: document.title,
description: document.querySelector('meta[name="description"]')?.content,
canonical: document.querySelector('link[rel="canonical"]')?.href,
h1: [...document.querySelectorAll('h1')].map((node) => node.textContent.trim()),
})Run the snippet in the browser Console, but compare it with the command-line result. If a signal exists only in the rendered DOM, it is still being added after the initial HTML response.
Measure SolidStart SEO performance in the field
Largest Contentful Paint by route type
Metric: Field LCP for public content, marketing, and other representative route groups.
What it tells you: Whether the largest visible content arrives promptly for real users; SSR helps only if data, images, and hosting complete the path.
How to pull it: Use CrUX or the Search Console Core Web Vitals report, segmented by similar URL groups where possible.
Benchmark / realistic range: Use Google’s current field-data classification and the site’s own pre-release baseline; do not substitute a synthetic framework benchmark for user data.
Cadence: Monthly and after a material rendering, hosting, or image-delivery change has accumulated field data.
Interaction to Next Paint
Metric: Field INP on interactive SolidJS routes.
What it tells you: Whether fine-grained updates translate into responsive real interactions rather than just favorable library benchmarks.
How to pull it: Use CrUX or Search Console, then reproduce poor page groups with browser performance tooling to find the long interaction.
Benchmark / realistic range: Compare with Google’s current classification and the route group’s own baseline; the framework alone does not establish a guaranteed range.
Cadence: Monthly and after adding large client-side components or third-party scripts.
Cumulative Layout Shift
Metric: Field CLS for SSR and streaming routes.
What it tells you: Whether hydration, streamed data, images, or late components move content after the initial HTML is displayed.
How to pull it: Use CrUX or Search Console for the standing KPI and DevTools for diagnosis on affected templates.
Benchmark / realistic range: Use Google’s current field-data classification and compare new releases with the established route baseline.
Cadence: Monthly and after changing streaming boundaries, image dimensions, or client-only components.
Patrick's relevant free tools
- SEO Incident Simulator — Practice thirty deterministic technical SEO incident investigations — indexability, crawl controls, redirects, sitemaps, markup, caching, DNS, bot verification, rendering, hreflang, and faceted navigation — with clearly labeled fixture evidence and Find → Fix → Verify handoffs.
- Raw vs. Rendered HTML Checker — See what's in your page's initial HTML versus after JavaScript runs — headless-Chrome rendering only when the page actually needs it, a rendering-strategy verdict (SSR / prerendered / CSR / hybrid), ~15 calibrated JavaScript-SEO checks (noindex, canonicals, robots.txt blocking, links, soft 404s), a side-by-side raw-vs-rendered diff, and shareable reports.
- Page Speed Test & Core Web Vitals Checker — One sentence tells you whether a page passes Core Web Vitals and what to fix first — real Chrome user data (CrUX) with a Lighthouse lab fallback, mobile and desktop side by side, loudly-labeled data sources, and prioritized diagnostic fixes. Plus a bulk origin scorecard with CSV export.
Tools for SolidJS SEO
- View Page Source (browser) — the fastest SSR check. If your content is in
the raw HTML (not just
<div id="root"></div>), SSR is working. - Google Search Console — URL Inspection — the source of truth for what Googlebot crawled and rendered; “View Tested Page → HTML” shows the rendered output.
- Rich Results Test — validate JSON-LD structured data on a SolidStart page.
- Bing Webmaster Tools — URL Inspection — shows Bing’s rendered version, important because Bing is more conservative about JavaScript than Google.
- Ahrefs Site Audit (JS rendering enabled) — crawl a SolidJS site the way a rendering crawler would, surfacing missing metadata and uncrawlable links.
solid-start-sitemap— build-time XML sitemap generation for SolidStart.- CrUX / Search Console Core Web Vitals report — confirm the INP/LCP/CLS advantage actually lands for real users, not just in the lab.
- DevTools Network tab — inspect the initial HTML response body to verify SSR content (vs. content injected after JS runs).
Test yourself: SolidJS SEO
Five quick questions on SolidJS, SolidStart, and getting a Solid site indexed. Pick an answer for each, then check.
Resources worth your time
My writing
- JavaScript SEO Issues & Best Practices — my definitive guide to rendering, DOM parity, crawlable links, and getting JS-built content indexed; the foundation a SolidJS site builds on.
- Core Web Vitals: A Complete Guide — what INP, LCP, and CLS measure and how they factor into SEO — the metrics SolidJS’s runtime helps with.
- The Beginner’s Guide to Technical SEO — where rendering and framework choice fit in the bigger picture.
My speaking
- SMX Advanced 2018: SEO for JavaScript Frameworks (SlideShare) — my walkthrough of how search engines handle JS frameworks.
- JavaScript SEO — Ungagged 2019 (SlideShare) — rendering modes, the two-wave process, and diagnosis.
From around the industry
- SolidStart — Head and Metadata — the primary-source guide to @solidjs/meta and SSR head tags.
- SolidStart — Route Pre-rendering — configuring SSG in
app.config.ts. - SolidJS — Fine-Grained Reactivity — signals and no-virtual-DOM updates straight from the docs.
- Google — Understand JavaScript SEO Basics — Google’s own rules for crawlable links, canonicals, and the rendering pipeline.
- solid-start-sitemap plugin — build-time XML sitemap generation for SolidStart.
- js-framework-benchmark (current results) — the long-running benchmark where SolidJS sits near the top and ahead of React on update-heavy work.
SolidJS SEO
SolidJS SEO is the set of practices for making SolidJS apps crawlable, indexable, and fast. Bare SolidJS renders client-side (an empty HTML shell), so SEO depends on using SolidStart for SSR or SSG to put real content and metadata in the initial HTML.
Related: JavaScript SEO
SolidJS SEO
SolidJS is a fine-grained reactive UI library with JSX syntax — similar in developer experience to React, but with no virtual DOM. Components run once, and reactive signals update only the exact DOM nodes that depend on a changed value, which is why SolidJS sits at or near the top of runtime benchmarks. The catch for SEO: out of the box, SolidJS is a client-side rendering (CSR) library. The server sends a near-empty HTML shell, the browser downloads and runs the JS, and only then does content appear — the same indexing problem that affects bare React, Vue, or Angular.
SolidStart is the official meta-framework (the SolidJS equivalent of Next.js or Nuxt). It adds server-side rendering, static site generation, streaming SSR, and file-based routing, so the first response contains fully rendered HTML — crawlable by Google on the first wave, and readable by Bing and social crawlers that may never execute JavaScript. Head tags are managed with the @solidjs/meta package (<Title>, <Meta>, <Link> components), and SolidStart’s <HttpStatusCode> lets routes return real HTTP status codes instead of soft 404s.
One distinction matters: SolidJS uses hydration, not resumability. Resumability is Qwik’s architecture. SolidJS’s fine-grained reactivity makes its hydration cheaper than React’s, but the client still downloads and executes the framework before the page is interactive — so the SEO win is largely a Core Web Vitals (INP/TBT) advantage layered on top of standard SSR.
Related: JavaScript SEO
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Updated Jul 18, 2026.
Editorial summary and recorded change details.Summary
Corrected the SolidStart router/metadata claim against the live docs (they are not auto-bundled — @solidjs/router and @solidjs/meta are explicit project choices), reframed 'SEO-viable' language to be per-route rather than project-wide, version-gated the rendering-mode list to SolidStart's current beta docs, and softened the Core Web Vitals section to avoid promising outcomes the framework alone can't guarantee.
Change details
-
Added a correction, verified live against docs.solidjs.com/solid-start, that SolidStart does not ship with a router or metadata library by default — file-based routing and @solidjs/meta are explicit additions the official templates happen to include, not automatic bundling.
-
Reframed the beginner TL;DR, the SolidStart feature list, and the cheat-sheet 'SEO verdict' row to state rendering mode and SEO viability as a per-route setting, not a whole-project guarantee.
-
Version-gated the rendering-mode list to match the live docs' current terminology (CSR, SSR — sync, async, or streaming — and SSG), noting SolidStart 1.0 is stable but its docs are still labeled beta as of their last update (4/28/26).
-
Softened the Core Web Vitals section from asserting SolidJS 'translates into real wins' to stating it 'can' improve CWV on SSR'd routes, contingent on data, images, and hosting — not the framework alone.
Full comparison unavailable — no prior snapshot was archived for this revision.