Qwik hydration/serialization mismatch during SSR in CI
Qwik resumes rather than hydrates: it serializes server state into the HTML and continues on the client. If the render depends on non-deterministic values or browser globals during SSR, the serialized state does not match and the resume warns or breaks.
What this error means
A CI prerender or e2e run reports a Qwik hydration/serialization mismatch, or the UI breaks on resume, because the server render used a value not reproducible on the client.
Warning: Qwik serialization mismatch: server state for signal "now"
does not match resumed client state.
server: 1700000000000 client: 1700000005000Common causes
Non-deterministic values in SSR render
Date.now()/Math.random() produce different server and client values, so the resumed state diverges.
Browser globals read during SSR
Reading window/document in useTask$ (which runs on the server) produces state the client cannot reproduce.
How to fix it
Keep SSR render deterministic; use useVisibleTask$
- Move time/random and DOM work into
useVisibleTask$, which runs only on the client. - Store only serializable, reproducible state in
useStore/useSignal. - Re-run the prerender to confirm the mismatch clears.
import { component$, useSignal, useVisibleTask$ } from '@builder.io/qwik';
export default component$(() => {
const now = useSignal(0); // stable across server + resume
useVisibleTask$(() => { now.value = Date.now(); });
return <time>{now.value}</time>;
});Avoid browser globals in server tasks
Do not read window/document in useTask$; that runs on the server and cannot match the client.
How to prevent it
- Keep SSR render deterministic and serializable.
- Do time/random/DOM work in
useVisibleTask$. - Store only reproducible state in Qwik signals/stores.