Skip to content

SSR or hydration breaks the page ​

The server has no window, document, MutationObserver, or real event loop. Browser-only initialization at module top level fails during SSR; placing it in first render can also cause hydration mismatch.

Symptoms ​

SymptomLikely cause
window is not definedBrowser code runs during module import
Hydration mismatchServer and client render different initial DOM
Actions unavailable on first paintPlugin installs after mount
Double registrationServer render and client initialize twice
Crash after route changeSingleton reused across requests
Leaked listenersPlugin teardown does not clean up

Vue / Nuxt ​

  • create createPling() inside a plugin or after onMounted;
  • do not share a module singleton across requests;
  • use a .client plugin or an explicit client condition;
  • keep server and client initial markup identical before hydration;
  • recreate page declarations on route change, or ensure scope cleanup is correct.

See Nuxt and SSR.

React / Next.js ​

  • use the provider in a client component and check the "use client" boundary;
  • never touch browser globals at module top level;
  • avoid rendering different DOM on the first render based on window;
  • create the runtime in an effect or after client mount;
  • do not pass non-serializable instances or functions from server components.

See Next.js and SSR.

Diagnostic order ​

  1. Find the first window / document access in server logs.
  2. Inspect hydration warnings and component boundaries in the browser.
  3. Disable Pling initialization and confirm base SSR works.
  4. Move runtime creation into a client lifecycle.
  5. Check duplicate plugin installation and singleton reuse across requests.
  6. Test a real production build, not only a dev server.

Security and consistency ​

An SSR page can return signed-out or placeholder markup first. Do not write protected data into server HTML and then let the client surface assume login. Revalidate identity per request; do not cache request sessions in a global module.

Acceptance ​

  • Server rendering accesses no browser API.
  • Hydration emits no structural mismatch warning.
  • Actions appear at a documented point after first paint.
  • Two concurrent requests do not share user state.
  • Route changes and unmount clean up listeners and registrations.
  • SSR and client behavior are tested in a production build.

Nuxt and SSR, Next.js and SSR, Projection: Shadow DOM and iframes.