Agent skill
solidstart-hydration-guard
SolidStart hydration guard: keep SSR/CSR output identical, gate browser-only APIs, use stable IDs, align Suspense/resource fallbacks, and use clientOnly/onMount for client-only UI.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/solidstart-hydration-guard
Metadata
Additional technical details for this skill
- globs
-
[ "src/app.tsx", "src/routes/**/*", "src/entry-*.tsx" ]
SKILL.md
SolidStart Hydration Guard
SSR/CSR Symmetry
- No browser-only globals during SSR: guard
window,document,localStorage,matchMedia,ResizeObserverwithif (!isServer)ortypeof window !== "undefined". - Keep server HTML stable: avoid
Math.random(),Date.now()in render; usecreateUniqueId()or values passed from server data. - Ensure Suspense fallbacks are the same server/client; don’t branch on browser checks for fallback.
- Avoid rendering different markup based on
isServerunless the client version is wrapped inclientOnlyor<NoHydration>.
Stable IDs & Data
- For IDs, use
createUniqueId()inside components, or pass stable IDs from server data/props. - Call
createUniqueId()the same number of times on server and client; don’t gate it behindisServeror<NoHydration>. - Only pass JSON-serializable data from server fetchers; avoid class instances/functions.
Resources & Suspense
- For
createResource/routercreateAsync, keepinitialValueconsistent between server and client. - Prefer
ssrLoadFrom: "server"when you need the server-rendered HTML to match hydration;"initial"will re-fetch on the client. - Use
onHydratedto inspect resource values during hydration when debugging. - Resources inside non-hydrating sections are not serialized; wrap client-needed data in
<Hydration>or pass it through props. - Use
deferStreamonly when you can set headers/status before flush; otherwise keep data in initial render to avoid mismatch.
Client-Only UI
- Wrap client-only components with
clientOnlyand provide a SSR-safe fallback. - For browser-only effects (e.g., viewport size), run inside
onMountorcreateEffectgated by!isServer. - Effects do not run during the initial client hydration, so they cannot fix initial mismatches.
<Portal>is client-only with hydration disabled; use it for overlays that should not hydrate.<NoHydration>skips hydration for its subtree; use<Hydration>to resume for interactive islands when needed.
Streaming & Headers
- When streaming (
renderToStream), setHttpHeader/HttpStatusCodebefore first flush; hydrate assumes status/headers are fixed.
Router Integration
- Wrap
<FileRoutes />with<Suspense>in the Router root to avoid hydration errors. - Keep route
preloadfunctions pure; SSR runs them and resumes on the client during hydration.
Document & Script Setup
- Include
<HydrationScript />once (SolidStart injects it via the documentassetsslot).
Debug Checklist
- Verify Router root uses
<Suspense>and that fallbacks match server/client. - Check for non-deterministic render output (
Math.random(),Date.now()). - Confirm
createUniqueId()call counts are identical on server/client. - Validate query args and server data are JSON-serializable.
- If you must render different client UI, isolate it with
clientOnly,<NoHydration>, or<Portal>.
Quick Checks
- Are all browser APIs guarded?
- Are IDs and fallbacks stable between server and client?
- Are Suspense boundaries identical on both sides?
Didn't find tool you were looking for?